diff --git a/.travis.yml b/.travis.yml index 2624ead..551a2ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,19 @@ language: go - go: - 1.6.3 - 1.7.3 + - 1.8 +install: + - export PATH=$PATH:$HOME/gopath/bin + - go get -u github.com/opennota/check/cmd/structcheck + - go get -u honnef.co/go/tools/cmd/gosimple + - go get -u honnef.co/go/tools/cmd/staticcheck + - go get -u honnef.co/go/tools/cmd/unused + - go get -u github.com/mdempsky/unconvert +script: + - go vet $(go list ./... | grep -v /vendor/) + - structcheck $(go list ./... | grep -v /vendor/) + - gosimple -ignore "github.com/beego/bee/cmd/commands/run/*.go:S1024" $(go list ./... | grep -v /vendor/) + - staticcheck $(go list ./... | grep -v /vendor/) + - unused $(go list ./... | grep -v /vendor/) + - unconvert $(go list ./... | grep -v /vendor/) diff --git a/Beefile b/Beefile index 16e5022..d77b2c5 100644 --- a/Beefile +++ b/Beefile @@ -1,7 +1,4 @@ version: 0 -gopm: - enable: false - install: false go_install: false watch_ext: [] dir_structure: diff --git a/README.md b/README.md index b264ffb..e4920a8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + bee === @@ -34,17 +35,20 @@ go get -u github.com/beego/bee Bee provides a variety of commands which can be helpful at various stages of development. The top level commands include: ``` - new Creates a Beego application - run Run the application by starting a local development server - pack Compresses a Beego application into a single file - api Creates a Beego API application - hprose Creates an RPC application based on Hprose and Beego frameworks - bale Transforms non-Go files to Go source files version Prints the current Bee version - generate Source code generator migrate Runs database migrations + api Creates a Beego API application + bale Transforms non-Go files to Go source files fix Fixes your application by making it compatible with newer versions of Beego + dlv Start a debugging session using Delve dockerize Generates a Dockerfile for your Beego application + generate Source code generator + hprose Creates an RPC application based on Hprose and Beego frameworks + new Creates a Beego application + pack Compresses a Beego application into a single file + rs Run customized scripts + run Run the application by starting a local development server + ``` ### bee version @@ -165,6 +169,38 @@ ______ For more information on the usage, run `bee help pack`. +### bee rs +Inspired by makefile / npm scripts. + Run script allows you to run arbitrary commands using Bee. + Custom commands are provided from the "scripts" object inside bee.json or Beefile. + + To run a custom command, use: $ bee rs mycmd ARGS + +```bash +$ bee help rs + +USAGE + bee rs + +DESCRIPTION + Run script allows you to run arbitrary commands using Bee. + Custom commands are provided from the "scripts" object inside bee.json or Beefile. + + To run a custom command, use: $ bee rs mycmd ARGS + +AVAILABLE SCRIPTS + gtest + APP_ENV=test APP_CONF_PATH=$(pwd)/conf go test -v -cover + gtestall + APP_ENV=test APP_CONF_PATH=$(pwd)/conf go test -v -cover $(go list ./... | grep -v /vendor/) + +``` + +*Run your scripts with:* +```$ bee rs gtest tests/*.go``` +```$ bee rs gtestall``` + + ### bee api To create a Beego API application: @@ -298,6 +334,37 @@ ______ For more information on the usage, run `bee help dockerize`. +### bee dlv + +Bee can also help with debugging your application. To start a debugging session: + +```bash +______ +| ___ \ +| |_/ / ___ ___ +| ___ \ / _ \ / _ \ +| |_/ /| __/| __/ +\____/ \___| \___| v1.8.0 +2017/03/22 11:17:05 INFO ▶ 0001 Starting Delve Debugger... +Type 'help' for list of commands. +(dlv) break main.main +Breakpoint 1 set at 0x40100f for main.main() ./main.go:8 + +(dlv) continue +> main.main() ./main.go:8 (hits goroutine(1):1 total:1) (PC: 0x40100f) + 3: import ( + 4: _ "github.com/user/myapp/routers" + 5: "github.com/astaxie/beego" + 6: ) + 7: +=> 8: func main() { + 9: beego.Run() + 10: } + 11: +``` + +For more information on the usage, run `bee help dlv`. + ## Shortcuts Because you'll likely type these generator commands over and over, it makes sense to create aliases: diff --git a/autorouter.go b/autorouter.go deleted file mode 100644 index 259f5da..0000000 --- a/autorouter.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main - -import ( - "bytes" - "errors" - "fmt" - "go/ast" - gobuild "go/build" - "go/doc" - "go/parser" - "go/token" - "io" - "io/ioutil" - "os" - "path" - "runtime" - "strings" - "time" -) - -var cmdRouter = &Command{ - UsageLine: "router", - Short: "auto-generate routers for the app controllers", - Long: ` - -`, -} - -func init() { - cmdRouter.Run = autoRouter -} - -func autoRouter(cmd *Command, args []string) int { - fmt.Println("[INFO] Starting auto-generating routers...") - return 0 -} - -// getControllerInfo returns controllers that embeded "beego.controller" -// and their methods of package in given path. -func getControllerInfo(path string) (map[string][]string, error) { - now := time.Now() - path = strings.TrimSuffix(path, "/") - dir, err := os.Open(path) - if err != nil { - return nil, err - } - - fis, err := dir.Readdir(0) - if err != nil { - return nil, err - } - - files := make([]*source, 0, len(fis)) - for _, fi := range fis { - // Only load Go files - if strings.HasSuffix(fi.Name(), ".go") { - f, err := os.Open(path + "/" + fi.Name()) - if err != nil { - return nil, err - } - - p := make([]byte, fi.Size()) - _, err = f.Read(p) - if err != nil { - return nil, err - } - - f.Close() - files = append(files, &source{ - name: path + "/" + fi.Name(), - data: p, - }) - } - } - - rw := &routerWalker{ - pdoc: &Package{ - ImportPath: path, - }, - } - - cm := make(map[string][]string) - pdoc, err := rw.build(files) - for _, t := range pdoc.Types { - // Check if embeded "beego.Controller". - if strings.Index(t.Decl, "beego.Controller") > -1 { - for _, f := range t.Methods { - cm[t.Name] = append(cm[t.Name], f.Name) - } - } - } - fmt.Println(time.Since(now)) - return cm, nil -} - -// source represents a source code file. -type source struct { - name string - data []byte -} - -func (s *source) Name() string { return s.name } -func (s *source) Size() int64 { return int64(len(s.data)) } -func (s *source) Mode() os.FileMode { return 0 } -func (s *source) ModTime() time.Time { return time.Time{} } -func (s *source) IsDir() bool { return false } -func (s *source) Sys() interface{} { return nil } - -// routerWalker holds the state used when building the documentation. -type routerWalker struct { - pdoc *Package - srcs map[string]*source // Source files - fset *token.FileSet - buf []byte // scratch space for printNode method -} - -// Package represents full information and documentation for a package. -type Package struct { - ImportPath string - Types []*Type // Top-level declarations -} - -// Type represents structs and interfaces. -type Type struct { - Name string // Type name - Decl string - Methods []*Func // Exported methods -} - -// Func represents functions -type Func struct { - Name string -} - -// build generates data from source files. -func (w *routerWalker) build(srcs []*source) (*Package, error) { - // Add source files to walker, I skipped references here - w.srcs = make(map[string]*source) - for _, src := range srcs { - w.srcs[src.name] = src - } - - w.fset = token.NewFileSet() - - // Find the package and associated files - ctxt := gobuild.Context{ - GOOS: runtime.GOOS, - GOARCH: runtime.GOARCH, - CgoEnabled: true, - JoinPath: path.Join, - IsAbsPath: path.IsAbs, - SplitPathList: func(list string) []string { return strings.Split(list, ":") }, - IsDir: func(path string) bool { panic("unexpected") }, - HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") }, - ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, - OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, - Compiler: "gc", - } - - bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0) - // Continue if there are no Go source files; we still want the directory info - _, nogo := err.(*gobuild.NoGoError) - if err != nil { - if nogo { - err = nil - } else { - return nil, errors.New("routerWalker.build -> " + err.Error()) - } - } - - // Parse the Go files - files := make(map[string]*ast.File) - for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { - file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) - if err != nil { - return nil, errors.New("routerWalker.build -> parse go files: " + err.Error()) - } - files[name] = file - } - - apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) - - mode := doc.Mode(0) - if w.pdoc.ImportPath == "builtin" { - mode |= doc.AllDecls - } - - pdoc := doc.New(apkg, w.pdoc.ImportPath, mode) - - w.pdoc.Types = w.types(pdoc.Types) - - return w.pdoc, err -} - -func (w *routerWalker) funcs(fdocs []*doc.Func) []*Func { - var result []*Func - for _, d := range fdocs { - result = append(result, &Func{ - Name: d.Name, - }) - } - return result -} - -func (w *routerWalker) types(tdocs []*doc.Type) []*Type { - var result []*Type - for _, d := range tdocs { - result = append(result, &Type{ - Decl: w.printDecl(d.Decl), - Name: d.Name, - Methods: w.funcs(d.Methods), - }) - } - return result -} - -func (w *routerWalker) printDecl(decl ast.Node) string { - var d Code - d, w.buf = printDecl(decl, w.fset, w.buf) - return d.Text -} - -func (w *routerWalker) readDir(dir string) ([]os.FileInfo, error) { - if dir != w.pdoc.ImportPath { - panic("unexpected") - } - fis := make([]os.FileInfo, 0, len(w.srcs)) - for _, src := range w.srcs { - fis = append(fis, src) - } - return fis, nil -} - -func (w *routerWalker) openFile(path string) (io.ReadCloser, error) { - if strings.HasPrefix(path, w.pdoc.ImportPath+"/") { - if src, ok := w.srcs[path[len(w.pdoc.ImportPath)+1:]]; ok { - return ioutil.NopCloser(bytes.NewReader(src.data)), nil - } - } - panic("unexpected") -} - -func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) { - pkg := imports[path] - if pkg == nil { - // Guess the package name without importing it. Start with the last - // element of the path. - name := path[strings.LastIndex(path, "/")+1:] - - // Trim commonly used prefixes and suffixes containing illegal name - // runes. - name = strings.TrimSuffix(name, ".go") - name = strings.TrimSuffix(name, "-go") - name = strings.TrimPrefix(name, "go.") - name = strings.TrimPrefix(name, "go-") - name = strings.TrimPrefix(name, "biogo.") - - // It's also common for the last element of the path to contain an - // extra "go" prefix, but not always. - // TODO: examine unresolved ids to detect when trimming the "go" prefix is appropriate. - pkg = ast.NewObj(ast.Pkg, name) - pkg.Data = ast.NewScope(nil) - imports[path] = pkg - } - return pkg, nil -} diff --git a/autorouter_test.go b/autorouter_test.go deleted file mode 100644 index 437f3ee..0000000 --- a/autorouter_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "testing" -) - -func TestGetControllerInfo(t *testing.T) { - getControllerInfo("testdata/router/") -} diff --git a/bee.go b/bee.go deleted file mode 100644 index 2c591b8..0000000 --- a/bee.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -// Bee is a tool for developing applications based on beego framework. -package main - -import ( - "flag" - "fmt" - "io" - "log" - "os" - "strings" - "text/template" -) - -const version = "1.8.0" - -// Command is the unit of execution -type Command struct { - // Run runs the command. - // The args are the arguments after the command name. - Run func(cmd *Command, args []string) int - - // PreRun performs an operation before running the command - PreRun func(cmd *Command, args []string) - - // UsageLine is the one-line usage message. - // The first word in the line is taken to be the command name. - UsageLine string - - // Short is the short description shown in the 'go help' output. - Short string - - // Long is the long message shown in the 'go help ' output. - Long string - - // Flag is a set of flags specific to this command. - Flag flag.FlagSet - - // CustomFlags indicates that the command will do its own - // flag parsing. - CustomFlags bool - - // output out writer if set in SetOutput(w) - output *io.Writer -} - -// Name returns the command's name: the first word in the usage line. -func (c *Command) Name() string { - name := c.UsageLine - i := strings.Index(name, " ") - if i >= 0 { - name = name[:i] - } - return name -} - -// SetOutput sets the destination for usage and error messages. -// If output is nil, os.Stderr is used. -func (c *Command) SetOutput(output io.Writer) { - c.output = &output -} - -// Out returns the out writer of the current command. -// If cmd.output is nil, os.Stderr is used. -func (c *Command) Out() io.Writer { - if c.output != nil { - return *c.output - } - return NewColorWriter(os.Stderr) -} - -// Usage puts out the usage for the command. -func (c *Command) Usage() { - tmpl(cmdUsage, c) - os.Exit(2) -} - -// Runnable reports whether the command can be run; otherwise -// it is a documentation pseudo-command such as import path. -func (c *Command) Runnable() bool { - return c.Run != nil -} - -func (c *Command) Options() map[string]string { - options := make(map[string]string) - c.Flag.VisitAll(func(f *flag.Flag) { - defaultVal := f.DefValue - if len(defaultVal) > 0 { - options[f.Name+"="+defaultVal] = f.Usage - } else { - options[f.Name] = f.Usage - } - }) - return options -} - -var availableCommands = []*Command{ - cmdNew, - cmdRun, - cmdPack, - cmdApiapp, - cmdHproseapp, - //cmdRouter, - //cmdTest, - cmdBale, - cmdVersion, - cmdGenerate, - //cmdRundocs, - cmdMigrate, - cmdFix, - cmdDockerize, -} - -var logger = GetBeeLogger(os.Stdout) - -func main() { - currentpath, _ := os.Getwd() - - flag.Usage = usage - flag.Parse() - log.SetFlags(0) - - args := flag.Args() - - if len(args) < 1 { - usage() - } - - if args[0] == "help" { - help(args[1:]) - return - } - - for _, cmd := range availableCommands { - if cmd.Name() == args[0] && cmd.Run != nil { - cmd.Flag.Usage = func() { cmd.Usage() } - if cmd.CustomFlags { - args = args[1:] - } else { - cmd.Flag.Parse(args[1:]) - args = cmd.Flag.Args() - } - - if cmd.PreRun != nil { - cmd.PreRun(cmd, args) - } - - // Check if current directory is inside the GOPATH, - // if so parse the packages inside it. - if IsInGOPATH(currentpath) && isGenerateDocs(cmd.Name(), args) { - parsePackagesFromDir(currentpath) - } - - os.Exit(cmd.Run(cmd, args)) - return - } - } - - printErrorAndExit("Unknown subcommand") -} - -func isGenerateDocs(name string, args []string) bool { - if name != "generate" { - return false - } - for _, a := range args { - if a == "docs" { - return true - } - } - return false -} - -var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application. - -{{"USAGE" | headline}} - {{"bee command [arguments]" | bold}} - -{{"AVAILABLE COMMANDS" | headline}} -{{range .}}{{if .Runnable}} - {{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}} - -Use {{"bee help [command]" | bold}} for more information about a command. - -{{"ADDITIONAL HELP TOPICS" | headline}} -{{range .}}{{if not .Runnable}} - {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} - -Use {{"bee help [topic]" | bold}} for more information about that topic. -` - -var helpTemplate = `{{"USAGE" | headline}} - {{.UsageLine | printf "bee %s" | bold}} -{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}} - {{$k | printf "-%s" | bold}} - {{$v}} - {{end}}{{end}} -{{"DESCRIPTION" | headline}} - {{tmpltostr .Long . | trim}} -` - -var errorTemplate = `bee: %s. -Use {{"bee help" | bold}} for more information. -` - -var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}` - -func usage() { - tmpl(usageTemplate, availableCommands) - os.Exit(2) -} - -func tmpl(text string, data interface{}) { - output := NewColorWriter(os.Stderr) - - t := template.New("usage").Funcs(BeeFuncMap()) - template.Must(t.Parse(text)) - - err := t.Execute(output, data) - MustCheck(err) -} - -func help(args []string) { - if len(args) == 0 { - usage() - } - if len(args) != 1 { - printErrorAndExit("Too many arguments") - } - - arg := args[0] - - for _, cmd := range availableCommands { - if cmd.Name() == arg { - tmpl(helpTemplate, cmd) - return - } - } - printErrorAndExit("Unknown help topic") -} - -func printErrorAndExit(message string) { - tmpl(fmt.Sprintf(errorTemplate, message), nil) - os.Exit(2) -} diff --git a/bee.json b/bee.json index e1bf758..50cbd0e 100644 --- a/bee.json +++ b/bee.json @@ -1,9 +1,5 @@ { "version": 0, - "gopm": { - "enable": false, - "install": false - }, "go_install": false, "watch_ext": [], "dir_structure": { diff --git a/cmd/bee.go b/cmd/bee.go new file mode 100644 index 0000000..8cf15aa --- /dev/null +++ b/cmd/bee.go @@ -0,0 +1,101 @@ +// Copyright 2013 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package cmd ... +package cmd + +import ( + "github.com/beego/bee/cmd/commands" + _ "github.com/beego/bee/cmd/commands/api" + _ "github.com/beego/bee/cmd/commands/bale" + _ "github.com/beego/bee/cmd/commands/beefix" + _ "github.com/beego/bee/cmd/commands/dlv" + _ "github.com/beego/bee/cmd/commands/dockerize" + _ "github.com/beego/bee/cmd/commands/generate" + _ "github.com/beego/bee/cmd/commands/hprose" + _ "github.com/beego/bee/cmd/commands/migrate" + _ "github.com/beego/bee/cmd/commands/new" + _ "github.com/beego/bee/cmd/commands/pack" + _ "github.com/beego/bee/cmd/commands/rs" + _ "github.com/beego/bee/cmd/commands/run" + _ "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/utils" +) + +func IfGenerateDocs(name string, args []string) bool { + if name != "generate" { + return false + } + for _, a := range args { + if a == "docs" { + return true + } + } + return false +} + +var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application. + +{{"USAGE" | headline}} + {{"bee command [arguments]" | bold}} + +{{"AVAILABLE COMMANDS" | headline}} +{{range .}}{{if .Runnable}} + {{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}} + +Use {{"bee help [command]" | bold}} for more information about a command. + +{{"ADDITIONAL HELP TOPICS" | headline}} +{{range .}}{{if not .Runnable}} + {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} + +Use {{"bee help [topic]" | bold}} for more information about that topic. +` + +var helpTemplate = `{{"USAGE" | headline}} + {{.UsageLine | printf "bee %s" | bold}} +{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}} + {{$k | printf "-%s" | bold}} + {{$v}} + {{end}}{{end}} +{{"DESCRIPTION" | headline}} + {{tmpltostr .Long . | trim}} +` + +var ErrorTemplate = `bee: %s. +Use {{"bee help" | bold}} for more information. +` + +func Usage() { + utils.Tmpl(usageTemplate, commands.AvailableCommands) +} + +func Help(args []string) { + if len(args) == 0 { + Usage() + } + if len(args) != 1 { + utils.PrintErrorAndExit("Too many arguments", ErrorTemplate) + } + + arg := args[0] + + for _, cmd := range commands.AvailableCommands { + if cmd.Name() == arg { + utils.Tmpl(helpTemplate, cmd) + return + } + } + utils.PrintErrorAndExit("Unknown help topic", ErrorTemplate) +} diff --git a/apiapp.go b/cmd/commands/api/apiapp.go similarity index 74% rename from apiapp.go rename to cmd/commands/api/apiapp.go index 3e2a9be..e1862be 100644 --- a/apiapp.go +++ b/cmd/commands/api/apiapp.go @@ -12,16 +12,22 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package apiapp import ( "fmt" "os" path "path/filepath" "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/generate" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" ) -var cmdApiapp = &Command{ +var CmdApiapp = &commands.Command{ // CustomFlags: true, UsageLine: "api [appname]", Short: "Creates a Beego API application", @@ -50,10 +56,9 @@ var cmdApiapp = &Command{ └── object.go └── user.go `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: createapi, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: createAPI, } - var apiconf = `appname = {{.Appname}} httpport = 8080 runmode = dev @@ -134,7 +139,7 @@ func init() { } ` -var apiModels = `package models +var APIModels = `package models import ( "errors" @@ -189,7 +194,7 @@ func Delete(ObjectId string) { ` -var apiModels2 = `package models +var APIModels2 = `package models import ( "errors" @@ -532,133 +537,101 @@ func TestGet(t *testing.T) { ` func init() { - cmdApiapp.Flag.Var(&tables, "tables", "List of table names separated by a comma.") - cmdApiapp.Flag.Var(&driver, "driver", "Database driver. Either mysql, postgres or sqlite.") - cmdApiapp.Flag.Var(&conn, "conn", "Connection string used by the driver to connect to a database instance.") + CmdApiapp.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.") + CmdApiapp.Flag.Var(&generate.SQLDriver, "driver", "Database driver. Either mysql, postgres or sqlite.") + CmdApiapp.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the driver to connect to a database instance.") + commands.AvailableCommands = append(commands.AvailableCommands, CmdApiapp) } -func createapi(cmd *Command, args []string) int { +func createAPI(cmd *commands.Command, args []string) int { output := cmd.Out() if len(args) < 1 { - logger.Fatal("Argument [appname] is missing") + beeLogger.Log.Fatal("Argument [appname] is missing") } if len(args) > 1 { - cmd.Flag.Parse(args[1:]) + err := cmd.Flag.Parse(args[1:]) + if err != nil { + beeLogger.Log.Error(err.Error()) + } } - apppath, packpath, err := checkEnv(args[0]) + appPath, packPath, err := utils.CheckEnv(args[0]) if err != nil { - logger.Fatalf("%s", err) + beeLogger.Log.Fatalf("%s", err) } - if driver == "" { - driver = "mysql" - } - if conn == "" { + if generate.SQLDriver == "" { + generate.SQLDriver = "mysql" } - logger.Info("Creating API...") + beeLogger.Log.Info("Creating API...") - os.MkdirAll(apppath, 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m") - os.Mkdir(path.Join(apppath, "conf"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m") - os.Mkdir(path.Join(apppath, "controllers"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers"), "\x1b[0m") - os.Mkdir(path.Join(apppath, "tests"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests"), "\x1b[0m") - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m") - WriteToFile(path.Join(apppath, "conf", "app.conf"), + os.MkdirAll(appPath, 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", appPath, "\x1b[0m") + os.Mkdir(path.Join(appPath, "conf"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "conf"), "\x1b[0m") + os.Mkdir(path.Join(appPath, "controllers"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers"), "\x1b[0m") + os.Mkdir(path.Join(appPath, "tests"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "tests"), "\x1b[0m") + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "conf", "app.conf"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "conf", "app.conf"), strings.Replace(apiconf, "{{.Appname}}", path.Base(args[0]), -1)) - if conn != "" { - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") - maingoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packpath, -1) - maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1) - if driver == "mysql" { - maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1) - } else if driver == "postgres" { - maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1) + if generate.SQLConn != "" { + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "main.go"), "\x1b[0m") + mainGoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packPath, -1) + mainGoContent = strings.Replace(mainGoContent, "{{.DriverName}}", string(generate.SQLDriver), -1) + if generate.SQLDriver == "mysql" { + mainGoContent = strings.Replace(mainGoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1) + } else if generate.SQLDriver == "postgres" { + mainGoContent = strings.Replace(mainGoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1) } - WriteToFile(path.Join(apppath, "main.go"), + utils.WriteToFile(path.Join(appPath, "main.go"), strings.Replace( - maingoContent, + mainGoContent, "{{.conn}}", - conn.String(), + generate.SQLConn.String(), -1, ), ) - logger.Infof("Using '%s' as 'driver'", driver) - logger.Infof("Using '%s' as 'conn'", conn) - logger.Infof("Using '%s' as 'tables'", tables) - generateAppcode(string(driver), string(conn), "3", string(tables), apppath) + beeLogger.Log.Infof("Using '%s' as 'driver'", generate.SQLDriver) + beeLogger.Log.Infof("Using '%s' as 'conn'", generate.SQLConn) + beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables) + generate.GenerateAppcode(string(generate.SQLDriver), string(generate.SQLConn), "3", string(generate.Tables), appPath) } else { - os.Mkdir(path.Join(apppath, "models"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m") - os.Mkdir(path.Join(apppath, "routers"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(appPath, "models"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models"), "\x1b[0m") + os.Mkdir(path.Join(appPath, "routers"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "routers")+string(path.Separator), "\x1b[0m") - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "object.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "controllers", "object.go"), - strings.Replace(apiControllers, "{{.Appname}}", packpath, -1)) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers", "object.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "controllers", "object.go"), + strings.Replace(apiControllers, "{{.Appname}}", packPath, -1)) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "user.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "controllers", "user.go"), - strings.Replace(apiControllers2, "{{.Appname}}", packpath, -1)) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers", "user.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "controllers", "user.go"), + strings.Replace(apiControllers2, "{{.Appname}}", packPath, -1)) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "tests", "default_test.go"), - strings.Replace(apiTests, "{{.Appname}}", packpath, -1)) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "tests", "default_test.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "tests", "default_test.go"), + strings.Replace(apiTests, "{{.Appname}}", packPath, -1)) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "routers", "router.go"), - strings.Replace(apirouter, "{{.Appname}}", packpath, -1)) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "routers", "router.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "routers", "router.go"), + strings.Replace(apirouter, "{{.Appname}}", packPath, -1)) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "models", "object.go"), apiModels) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models", "object.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "models", "object.go"), APIModels) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models", "user.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "models", "user.go"), APIModels2) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "main.go"), - strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "main.go"), "\x1b[0m") + utils.WriteToFile(path.Join(appPath, "main.go"), + strings.Replace(apiMaingo, "{{.Appname}}", packPath, -1)) } - logger.Success("New API successfully created!") + beeLogger.Log.Success("New API successfully created!") return 0 } - -func checkEnv(appname string) (apppath, packpath string, err error) { - gps := GetGOPATHs() - if len(gps) == 0 { - logger.Fatal("GOPATH environment variable is not set or empty") - } - currpath, _ := os.Getwd() - currpath = path.Join(currpath, appname) - for _, gpath := range gps { - gsrcpath := path.Join(gpath, "src") - if strings.HasPrefix(currpath, gsrcpath) { - packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(path.Separator), "/", -1) - return currpath, packpath, nil - } - } - - // In case of multiple paths in the GOPATH, by default - // we use the first path - gopath := gps[0] - - logger.Warn("You current workdir is not inside $GOPATH/src.") - logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath) - - gosrcpath := path.Join(gopath, "src") - apppath = path.Join(gosrcpath, appname) - - if _, e := os.Stat(apppath); os.IsNotExist(e) == false { - err = fmt.Errorf("Cannot create application without removing '%s' first.", apppath) - logger.Errorf("Path '%s' already exists", apppath) - return - } - packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/") - return -} diff --git a/bale.go b/cmd/commands/bale/bale.go similarity index 79% rename from bale.go rename to cmd/commands/bale/bale.go index 2cd6667..8ba9641 100644 --- a/bale.go +++ b/cmd/commands/bale/bale.go @@ -11,8 +11,7 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. - -package main +package bale import ( "bytes" @@ -24,9 +23,15 @@ import ( "path/filepath" "runtime" "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/config" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" ) -var cmdBale = &Command{ +var CmdBale = &commands.Command{ UsageLine: "bale", Short: "Transforms non-Go files to Go source files", Long: `Bale command compress all the static files in to a single binary file. @@ -37,47 +42,46 @@ var cmdBale = &Command{ It will auto-generate an unpack function to the main package then run it during the runtime. This is mainly used for zealots who are requiring 100% Go code. `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, Run: runBale, } -func runBale(cmd *Command, args []string) int { - err := loadConfig() - if err != nil { - logger.Fatalf("Failed to load configuration: %s", err) - } +func init() { + commands.AvailableCommands = append(commands.AvailableCommands, CmdBale) +} +func runBale(cmd *commands.Command, args []string) int { os.RemoveAll("bale") os.Mkdir("bale", os.ModePerm) // Pack and compress data - for _, p := range conf.Bale.Dirs { - if !isExist(p) { - logger.Warnf("Skipped directory: %s", p) + for _, p := range config.Conf.Bale.Dirs { + if !utils.IsExist(p) { + beeLogger.Log.Warnf("Skipped directory: %s", p) continue } - logger.Infof("Packaging directory: %s", p) + beeLogger.Log.Infof("Packaging directory: %s", p) filepath.Walk(p, walkFn) } // Generate auto-uncompress function. buf := new(bytes.Buffer) - buf.WriteString(fmt.Sprintf(BaleHeader, conf.Bale.Import, + buf.WriteString(fmt.Sprintf(BaleHeader, config.Conf.Bale.Import, strings.Join(resFiles, "\",\n\t\t\""), strings.Join(resFiles, ",\n\t\tbale.R"))) fw, err := os.Create("bale.go") if err != nil { - logger.Fatalf("Failed to create file: %s", err) + beeLogger.Log.Fatalf("Failed to create file: %s", err) } defer fw.Close() _, err = fw.Write(buf.Bytes()) if err != nil { - logger.Fatalf("Failed to write data: %s", err) + beeLogger.Log.Fatalf("Failed to write data: %s", err) } - logger.Success("Baled resources successfully!") + beeLogger.Log.Success("Baled resources successfully!") return 0 } @@ -138,7 +142,7 @@ func saveFile(filePath string, b []byte) (int, error) { var resFiles = make([]string, 0, 10) -func walkFn(resPath string, info os.FileInfo, err error) error { +func walkFn(resPath string, info os.FileInfo, _ error) error { if info.IsDir() || filterSuffix(resPath) { return nil } @@ -146,7 +150,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error { // Open resource files fr, err := os.Open(resPath) if err != nil { - logger.Fatalf("Failed to read file: %s", err) + beeLogger.Log.Fatalf("Failed to read file: %s", err) } // Convert path @@ -164,7 +168,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error { os.MkdirAll(path.Dir(resPath), os.ModePerm) fw, err := os.Create("bale/" + resPath + ".go") if err != nil { - logger.Fatalf("Failed to create file: %s", err) + beeLogger.Log.Fatalf("Failed to create file: %s", err) } defer fw.Close() @@ -184,7 +188,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error { } func filterSuffix(name string) bool { - for _, s := range conf.Bale.IngExt { + for _, s := range config.Conf.Bale.IngExt { if strings.HasSuffix(name, s) { return true } diff --git a/fix.go b/cmd/commands/beefix/fix.go similarity index 91% rename from fix.go rename to cmd/commands/beefix/fix.go index 13453e6..1345bf0 100644 --- a/fix.go +++ b/cmd/commands/beefix/fix.go @@ -1,4 +1,4 @@ -package main +package beefix import ( "fmt" @@ -9,9 +9,14 @@ import ( "path/filepath" "regexp" "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" ) -var cmdFix = &Command{ +var CmdFix = &commands.Command{ UsageLine: "fix", Short: "Fixes your application by making it compatible with newer versions of Beego", Long: `As of {{"Beego 1.6"|bold}}, there are some backward compatibility issues. @@ -22,18 +27,19 @@ var cmdFix = &Command{ } func init() { - cmdFix.Run = runFix - cmdFix.PreRun = func(cmd *Command, args []string) { ShowShortVersionBanner() } + CmdFix.Run = runFix + CmdFix.PreRun = func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() } + commands.AvailableCommands = append(commands.AvailableCommands, CmdFix) } -func runFix(cmd *Command, args []string) int { +func runFix(cmd *commands.Command, args []string) int { output := cmd.Out() - logger.Info("Upgrading the application...") + beeLogger.Log.Info("Upgrading the application...") dir, err := os.Getwd() if err != nil { - logger.Fatalf("Error while getting the current working directory: %s", err) + beeLogger.Log.Fatalf("Error while getting the current working directory: %s", err) } filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { @@ -50,13 +56,13 @@ func runFix(cmd *Command, args []string) int { return nil } err = fixFile(path) - fmt.Fprintf(output, GreenBold("\tfix\t")+"%s\n", path) + fmt.Fprintf(output, colors.GreenBold("\tfix\t")+"%s\n", path) if err != nil { - logger.Errorf("Could not fix file: %s", err) + beeLogger.Log.Errorf("Could not fix file: %s", err) } return err }) - logger.Success("Upgrade Done!") + beeLogger.Log.Success("Upgrade Done!") return 0 } diff --git a/cmd/commands/command.go b/cmd/commands/command.go new file mode 100644 index 0000000..cab663f --- /dev/null +++ b/cmd/commands/command.go @@ -0,0 +1,94 @@ +package commands + +import ( + "flag" + "io" + "os" + "strings" + + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" +) + +// Command is the unit of execution +type Command struct { + // Run runs the command. + // The args are the arguments after the command name. + Run func(cmd *Command, args []string) int + + // PreRun performs an operation before running the command + PreRun func(cmd *Command, args []string) + + // UsageLine is the one-line Usage message. + // The first word in the line is taken to be the command name. + UsageLine string + + // Short is the short description shown in the 'go help' output. + Short string + + // Long is the long message shown in the 'go help ' output. + Long string + + // Flag is a set of flags specific to this command. + Flag flag.FlagSet + + // CustomFlags indicates that the command will do its own + // flag parsing. + CustomFlags bool + + // output out writer if set in SetOutput(w) + output *io.Writer +} + +var AvailableCommands = []*Command{} +var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}` + +// Name returns the command's name: the first word in the Usage line. +func (c *Command) Name() string { + name := c.UsageLine + i := strings.Index(name, " ") + if i >= 0 { + name = name[:i] + } + return name +} + +// SetOutput sets the destination for Usage and error messages. +// If output is nil, os.Stderr is used. +func (c *Command) SetOutput(output io.Writer) { + c.output = &output +} + +// Out returns the out writer of the current command. +// If cmd.output is nil, os.Stderr is used. +func (c *Command) Out() io.Writer { + if c.output != nil { + return *c.output + } + return colors.NewColorWriter(os.Stderr) +} + +// Usage puts out the Usage for the command. +func (c *Command) Usage() { + utils.Tmpl(cmdUsage, c) + os.Exit(2) +} + +// Runnable reports whether the command can be run; otherwise +// it is a documentation pseudo-command such as import path. +func (c *Command) Runnable() bool { + return c.Run != nil +} + +func (c *Command) Options() map[string]string { + options := make(map[string]string) + c.Flag.VisitAll(func(f *flag.Flag) { + defaultVal := f.DefValue + if len(defaultVal) > 0 { + options[f.Name+"="+defaultVal] = f.Usage + } else { + options[f.Name] = f.Usage + } + }) + return options +} diff --git a/cmd/commands/dlv/dlv.go b/cmd/commands/dlv/dlv.go new file mode 100644 index 0000000..ec0dafa --- /dev/null +++ b/cmd/commands/dlv/dlv.go @@ -0,0 +1,135 @@ +// Copyright 2017 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package dlv ... +package dlv + +import ( + "flag" + "fmt" + "net" + "os" + "path/filepath" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" + "github.com/derekparker/delve/pkg/terminal" + "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/rpc2" + "github.com/derekparker/delve/service/rpccommon" +) + +var cmdDlv = &commands.Command{ + CustomFlags: true, + UsageLine: "dlv [-package=\"\"] [-port=8181]", + Short: "Start a debugging session using Delve", + Long: `dlv command start a debugging session using debugging tool Delve. + + To debug your application using Delve, use: {{"$ bee dlv" | bold}} + + For more information on Delve: https://github.com/derekparker/delve +`, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: runDlv, +} + +var ( + packageName string + port int +) + +func init() { + fs := flag.NewFlagSet("dlv", flag.ContinueOnError) + fs.IntVar(&port, "port", 8181, "Port to listen to for clients") + fs.StringVar(&packageName, "package", "", "The package to debug (Must have a main package)") + cmdDlv.Flag = *fs + commands.AvailableCommands = append(commands.AvailableCommands, cmdDlv) +} + +func runDlv(cmd *commands.Command, args []string) int { + if err := cmd.Flag.Parse(args); err != nil { + beeLogger.Log.Fatalf("Error parsing flags: %v", err.Error()) + } + + debugname := "debug" + addr := fmt.Sprintf("127.0.0.1:%d", port) + return runDelve(addr, debugname) +} + +// runDelve runs the Delve debugger server +func runDelve(addr, debugname string) int { + beeLogger.Log.Info("Starting Delve Debugger...") + + err := gobuild(debugname, packageName) + if err != nil { + beeLogger.Log.Fatalf("%v", err) + } + + fp, err := filepath.Abs("./" + debugname) + if err != nil { + beeLogger.Log.Fatalf("%v", err) + } + defer os.Remove(fp) + + abs, err := filepath.Abs(debugname) + if err != nil { + beeLogger.Log.Fatalf("%v", err) + } + + // Create and start the debugger server + listener, err := net.Listen("tcp", addr) + if err != nil { + beeLogger.Log.Fatalf("Could not start listener: %s", err) + } + defer listener.Close() + + server := rpccommon.NewServer(&service.Config{ + Listener: listener, + AcceptMulti: true, + AttachPid: 0, + APIVersion: 2, + WorkingDir: "./", + ProcessArgs: []string{abs}, + }, false) + if err := server.Run(); err != nil { + beeLogger.Log.Fatalf("Could not start debugger server: %v", err) + } + + // Start the Delve client REPL + client := rpc2.NewClient(addr) + term := terminal.New(client, nil) + + status, err := term.Run() + if err != nil { + beeLogger.Log.Fatalf("Could not start Delve REPL: %v", err) + } + defer term.Close() + + // Stop and kill the debugger server once + // user quits the REPL + if err := server.Stop(true); err != nil { + beeLogger.Log.Fatalf("Could not stop Delve server: %v", err) + } + return status +} + +// gobuild runs the "go build" command on the specified package +func gobuild(debugname, pkg string) error { + args := []string{"-gcflags", "-N -l", "-o", debugname} + args = append(args, utils.SplitQuotedFields("-ldflags='-linkmode internal'")...) + args = append(args, pkg) + return utils.GoCommand("build", args...) +} diff --git a/dockerize.go b/cmd/commands/dockerize/dockerize.go similarity index 74% rename from dockerize.go rename to cmd/commands/dockerize/dockerize.go index 827fc8e..3aad82e 100644 --- a/dockerize.go +++ b/cmd/commands/dockerize/dockerize.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package dockerize import ( "flag" @@ -21,22 +21,13 @@ import ( "path/filepath" "strings" "text/template" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" ) -var cmdDockerize = &Command{ - CustomFlags: true, - UsageLine: "dockerize", - Short: "Generates a Dockerfile for your Beego application", - Long: `Dockerize generates a Dockerfile for your Beego Web Application. - The Dockerfile will compile, get the dependencies with {{"godep"|bold}}, and set the entrypoint. - - {{"Example:"|bold}} - $ bee dockerize -expose="3000,80,25" - `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: dockerizeApp, -} - const dockerBuildTemplate = `FROM {{.BaseImage}} # Godep for vendoring @@ -49,12 +40,11 @@ ENV APP_DIR $GOPATH{{.Appdir}} RUN mkdir -p $APP_DIR # Set the entrypoint -ENTRYPOINT $APP_DIR/{{.Entrypoint}} +ENTRYPOINT (cd $APP_DIR && ./{{.Entrypoint}}) ADD . $APP_DIR # Compile the binary and statically link -RUN cd $APP_DIR -RUN CGO_ENABLED=0 godep go build -ldflags '-d -w -s' +RUN cd $APP_DIR && CGO_ENABLED=0 godep go build -ldflags '-d -w -s' EXPOSE {{.Expose}} ` @@ -67,6 +57,20 @@ type Dockerfile struct { Expose string } +var CmdDockerize = &commands.Command{ + CustomFlags: true, + UsageLine: "dockerize", + Short: "Generates a Dockerfile for your Beego application", + Long: `Dockerize generates a Dockerfile for your Beego Web Application. + The Dockerfile will compile, get the dependencies with {{"godep"|bold}}, and set the entrypoint. + + {{"Example:"|bold}} + $ bee dockerize -expose="3000,80,25" + `, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: dockerizeApp, +} + var ( expose string baseImage string @@ -76,19 +80,22 @@ func init() { fs := flag.NewFlagSet("dockerize", flag.ContinueOnError) fs.StringVar(&baseImage, "image", "library/golang", "Set the base image of the Docker container.") fs.StringVar(&expose, "expose", "8080", "Port(s) to expose in the Docker container.") - cmdDockerize.Flag = *fs + CmdDockerize.Flag = *fs + commands.AvailableCommands = append(commands.AvailableCommands, CmdDockerize) } -func dockerizeApp(cmd *Command, args []string) int { +func dockerizeApp(cmd *commands.Command, args []string) int { if err := cmd.Flag.Parse(args); err != nil { - logger.Fatalf("Error parsing flags: %v", err.Error()) + beeLogger.Log.Fatalf("Error parsing flags: %v", err.Error()) } - logger.Info("Generating Dockerfile...") + beeLogger.Log.Info("Generating Dockerfile...") gopath := os.Getenv("GOPATH") dir, err := filepath.Abs(".") - MustCheck(err) + if err != nil { + beeLogger.Log.Error(err.Error()) + } appdir := strings.Replace(dir, gopath, "", 1) @@ -112,15 +119,15 @@ func dockerizeApp(cmd *Command, args []string) int { } func generateDockerfile(df Dockerfile) { - t := template.Must(template.New("dockerBuildTemplate").Parse(dockerBuildTemplate)).Funcs(BeeFuncMap()) + t := template.Must(template.New("dockerBuildTemplate").Parse(dockerBuildTemplate)).Funcs(utils.BeeFuncMap()) f, err := os.Create("Dockerfile") if err != nil { - logger.Fatalf("Error writing Dockerfile: %v", err.Error()) + beeLogger.Log.Fatalf("Error writing Dockerfile: %v", err.Error()) } - defer CloseFile(f) + defer utils.CloseFile(f) t.Execute(f, df) - logger.Success("Dockerfile generated.") + beeLogger.Log.Success("Dockerfile generated.") } diff --git a/cmd/commands/generate/generate.go b/cmd/commands/generate/generate.go new file mode 100644 index 0000000..edf4691 --- /dev/null +++ b/cmd/commands/generate/generate.go @@ -0,0 +1,216 @@ +// Copyright 2013 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +package generate + +import ( + "os" + "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/config" + "github.com/beego/bee/generate" + "github.com/beego/bee/generate/swaggergen" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" +) + +var CmdGenerate = &commands.Command{ + UsageLine: "generate [command]", + Short: "Source code generator", + Long: `▶ {{"To scaffold out your entire application:"|bold}} + + $ bee generate scaffold [scaffoldname] [-fields="title:string,body:text"] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] + + ▶ {{"To generate a Model based on fields:"|bold}} + + $ bee generate model [modelname] [-fields="name:type"] + + ▶ {{"To generate a controller:"|bold}} + + $ bee generate controller [controllerfile] + + ▶ {{"To generate a CRUD view:"|bold}} + + $ bee generate view [viewpath] + + ▶ {{"To generate a migration file for making database schema updates:"|bold}} + + $ bee generate migration [migrationfile] [-fields="name:type"] + + ▶ {{"To generate swagger doc file:"|bold}} + + $ bee generate docs + + ▶ {{"To generate a test case:"|bold}} + + $ bee generate test [routerfile] + + ▶ {{"To generate appcode based on an existing database:"|bold}} + + $ bee generate appcode [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3] +`, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: GenerateCode, +} + +func init() { + CmdGenerate.Flag.Var(&generate.Tables, "Tables", "List of table names separated by a comma.") + CmdGenerate.Flag.Var(&generate.SQLDriver, "SQLDriver", "Database SQLDriver. Either mysql, postgres or sqlite.") + CmdGenerate.Flag.Var(&generate.SQLConn, "SQLConn", "Connection string used by the SQLDriver to connect to a database instance.") + CmdGenerate.Flag.Var(&generate.Level, "Level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.") + CmdGenerate.Flag.Var(&generate.Fields, "Fields", "List of table Fields.") + commands.AvailableCommands = append(commands.AvailableCommands, CmdGenerate) +} + +func GenerateCode(cmd *commands.Command, args []string) int { + currpath, _ := os.Getwd() + if len(args) < 1 { + beeLogger.Log.Fatal("Command is missing") + } + + gps := utils.GetGOPATHs() + if len(gps) == 0 { + beeLogger.Log.Fatal("GOPATH environment variable is not set or empty") + } + + gopath := gps[0] + + beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath) + + gcmd := args[0] + switch gcmd { + case "scaffold": + scaffold(cmd, args, currpath) + case "docs": + swaggergen.GenerateDocs(currpath) + case "appcode": + appCode(cmd, args, currpath) + case "migration": + migration(cmd, args, currpath) + case "controller": + controller(args, currpath) + case "model": + model(cmd, args, currpath) + case "view": + view(args, currpath) + default: + beeLogger.Log.Fatal("Command is missing") + } + beeLogger.Log.Successf("%s successfully generated!", strings.Title(gcmd)) + return 0 +} + +func scaffold(cmd *commands.Command, args []string, currpath string) { + if len(args) < 2 { + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } + + cmd.Flag.Parse(args[2:]) + if generate.SQLDriver == "" { + generate.SQLDriver = utils.DocValue(config.Conf.Database.Driver) + if generate.SQLDriver == "" { + generate.SQLDriver = "mysql" + } + } + if generate.SQLConn == "" { + generate.SQLConn = utils.DocValue(config.Conf.Database.Conn) + if generate.SQLConn == "" { + generate.SQLConn = "root:@tcp(127.0.0.1:3306)/test" + } + } + if generate.Fields == "" { + beeLogger.Log.Hint("Fields option should not be empty, i.e. -Fields=\"title:string,body:text\"") + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } + sname := args[1] + generate.GenerateScaffold(sname, generate.Fields.String(), currpath, generate.SQLDriver.String(), generate.SQLConn.String()) +} + +func appCode(cmd *commands.Command, args []string, currpath string) { + cmd.Flag.Parse(args[1:]) + if generate.SQLDriver == "" { + generate.SQLDriver = utils.DocValue(config.Conf.Database.Driver) + if generate.SQLDriver == "" { + generate.SQLDriver = "mysql" + } + } + if generate.SQLConn == "" { + generate.SQLConn = utils.DocValue(config.Conf.Database.Conn) + if generate.SQLConn == "" { + if generate.SQLDriver == "mysql" { + generate.SQLConn = "root:@tcp(127.0.0.1:3306)/test" + } else if generate.SQLDriver == "postgres" { + generate.SQLConn = "postgres://postgres:postgres@127.0.0.1:5432/postgres" + } + } + } + if generate.Level == "" { + generate.Level = "3" + } + beeLogger.Log.Infof("Using '%s' as 'SQLDriver'", generate.SQLDriver) + beeLogger.Log.Infof("Using '%s' as 'SQLConn'", generate.SQLConn) + beeLogger.Log.Infof("Using '%s' as 'Tables'", generate.Tables) + beeLogger.Log.Infof("Using '%s' as 'Level'", generate.Level) + generate.GenerateAppcode(generate.SQLDriver.String(), generate.SQLConn.String(), generate.Level.String(), generate.Tables.String(), currpath) +} +func migration(cmd *commands.Command, args []string, currpath string) { + if len(args) < 2 { + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } + cmd.Flag.Parse(args[2:]) + mname := args[1] + + beeLogger.Log.Infof("Using '%s' as migration name", mname) + + upsql := "" + downsql := "" + if generate.Fields != "" { + dbMigrator := generate.NewDBDriver() + upsql = dbMigrator.GenerateCreateUp(mname) + downsql = dbMigrator.GenerateCreateDown(mname) + } + generate.GenerateMigration(mname, upsql, downsql, currpath) +} + +func controller(args []string, currpath string) { + if len(args) == 2 { + cname := args[1] + generate.GenerateController(cname, currpath) + } else { + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } +} + +func model(cmd *commands.Command, args []string, currpath string) { + if len(args) < 2 { + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } + cmd.Flag.Parse(args[2:]) + if generate.Fields == "" { + beeLogger.Log.Hint("Fields option should not be empty, i.e. -Fields=\"title:string,body:text\"") + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } + sname := args[1] + generate.GenerateModel(sname, generate.Fields.String(), currpath) +} + +func view(args []string, currpath string) { + if len(args) == 2 { + cname := args[1] + generate.GenerateView(cname, currpath) + } else { + beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate") + } +} diff --git a/cmd/commands/hprose/hprose.go b/cmd/commands/hprose/hprose.go new file mode 100644 index 0000000..135070f --- /dev/null +++ b/cmd/commands/hprose/hprose.go @@ -0,0 +1,119 @@ +package hprose + +import ( + "os" + + "fmt" + "path" + "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/api" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/generate" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" +) + +var CmdHproseapp = &commands.Command{ + // CustomFlags: true, + UsageLine: "hprose [appname]", + Short: "Creates an RPC application based on Hprose and Beego frameworks", + Long: ` + The command 'hprose' creates an RPC application based on both Beego and Hprose (http://hprose.com/). + + {{"To scaffold out your application, use:"|bold}} + + $ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test] + + If 'conn' is empty, the command will generate a sample application. Otherwise the command + will connect to your database and generate models based on the existing tables. + + The command 'hprose' creates a folder named [appname] with the following structure: + + ├── main.go + ├── {{"conf"|foldername}} + │ └── app.conf + └── {{"models"|foldername}} + └── object.go + └── user.go +`, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: createhprose, +} + +func init() { + CmdHproseapp.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.") + CmdHproseapp.Flag.Var(&generate.SQLDriver, "driver", "Database driver. Either mysql, postgres or sqlite.") + CmdHproseapp.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the driver to connect to a database instance.") + commands.AvailableCommands = append(commands.AvailableCommands, CmdHproseapp) +} + +func createhprose(cmd *commands.Command, args []string) int { + output := cmd.Out() + + if len(args) != 1 { + beeLogger.Log.Fatal("Argument [appname] is missing") + } + + curpath, _ := os.Getwd() + if len(args) > 1 { + cmd.Flag.Parse(args[1:]) + } + apppath, packpath, err := utils.CheckEnv(args[0]) + if err != nil { + beeLogger.Log.Fatalf("%s", err) + } + if generate.SQLDriver == "" { + generate.SQLDriver = "mysql" + } + beeLogger.Log.Info("Creating Hprose application...") + + os.MkdirAll(apppath, 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m") + os.Mkdir(path.Join(apppath, "conf"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m") + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "conf", "app.conf"), + strings.Replace(generate.Hproseconf, "{{.Appname}}", args[0], -1)) + + if generate.SQLConn != "" { + beeLogger.Log.Infof("Using '%s' as 'driver'", generate.SQLDriver) + beeLogger.Log.Infof("Using '%s' as 'conn'", generate.SQLConn) + beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables) + generate.GenerateHproseAppcode(string(generate.SQLDriver), string(generate.SQLConn), "1", string(generate.Tables), path.Join(curpath, args[0])) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") + maingoContent := strings.Replace(generate.HproseMainconngo, "{{.Appname}}", packpath, -1) + maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(generate.SQLDriver), -1) + maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(generate.HproseAddFunctions, ""), -1) + if generate.SQLDriver == "mysql" { + maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1) + } else if generate.SQLDriver == "postgres" { + maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1) + } + utils.WriteToFile(path.Join(apppath, "main.go"), + strings.Replace( + maingoContent, + "{{.conn}}", + generate.SQLConn.String(), + -1, + ), + ) + } else { + os.Mkdir(path.Join(apppath, "models"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m") + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "models", "object.go"), apiapp.APIModels) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "models", "user.go"), apiapp.APIModels2) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "main.go"), + strings.Replace(generate.HproseMaingo, "{{.Appname}}", packpath, -1)) + } + beeLogger.Log.Success("New Hprose application successfully created!") + return 0 +} diff --git a/migrate.go b/cmd/commands/migrate/migrate.go similarity index 73% rename from migrate.go rename to cmd/commands/migrate/migrate.go index 5ef4681..1870945 100644 --- a/migrate.go +++ b/cmd/commands/migrate/migrate.go @@ -11,8 +11,7 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. - -package main +package migrate import ( "database/sql" @@ -23,9 +22,16 @@ import ( "strconv" "strings" "time" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/config" + "github.com/beego/bee/utils" + + beeLogger "github.com/beego/bee/logger" ) -var cmdMigrate = &Command{ +var CmdMigrate = &commands.Command{ UsageLine: "migrate [Command]", Short: "Runs database migrations", Long: `The command 'migrate' allows you to run database migrations to keep it up-to-date. @@ -46,100 +52,75 @@ var cmdMigrate = &Command{ $ bee migrate refresh [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: runMigration, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: RunMigration, } -var mDriver docValue -var mConn docValue +var mDriver utils.DocValue +var mConn utils.DocValue func init() { - cmdMigrate.Flag.Var(&mDriver, "driver", "Database driver. Either mysql, postgres or sqlite.") - cmdMigrate.Flag.Var(&mConn, "conn", "Connection string used by the driver to connect to a database instance.") + CmdMigrate.Flag.Var(&mDriver, "driver", "Database driver. Either mysql, postgres or sqlite.") + CmdMigrate.Flag.Var(&mConn, "conn", "Connection string used by the driver to connect to a database instance.") + commands.AvailableCommands = append(commands.AvailableCommands, CmdMigrate) } // runMigration is the entry point for starting a migration -func runMigration(cmd *Command, args []string) int { +func RunMigration(cmd *commands.Command, args []string) int { currpath, _ := os.Getwd() - gps := GetGOPATHs() + gps := utils.GetGOPATHs() if len(gps) == 0 { - logger.Fatal("GOPATH environment variable is not set or empty") + beeLogger.Log.Fatal("GOPATH environment variable is not set or empty") } gopath := gps[0] - logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath) - - // Load the configuration - err := loadConfig() - if err != nil { - logger.Errorf("Failed to load configuration: %s", err) - } + beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath) // Getting command line arguments if len(args) != 0 { cmd.Flag.Parse(args[1:]) } if mDriver == "" { - mDriver = docValue(conf.Database.Driver) + mDriver = utils.DocValue(config.Conf.Database.Driver) if mDriver == "" { mDriver = "mysql" } } if mConn == "" { - mConn = docValue(conf.Database.Conn) + mConn = utils.DocValue(config.Conf.Database.Conn) if mConn == "" { mConn = "root:@tcp(127.0.0.1:3306)/test" } } - logger.Infof("Using '%s' as 'driver'", mDriver) - logger.Infof("Using '%s' as 'conn'", mConn) + beeLogger.Log.Infof("Using '%s' as 'driver'", mDriver) + beeLogger.Log.Infof("Using '%s' as 'conn'", mConn) driverStr, connStr := string(mDriver), string(mConn) if len(args) == 0 { // run all outstanding migrations - logger.Info("Running all outstanding migrations") - migrateUpdate(currpath, driverStr, connStr) + beeLogger.Log.Info("Running all outstanding migrations") + MigrateUpdate(currpath, driverStr, connStr) } else { mcmd := args[0] switch mcmd { case "rollback": - logger.Info("Rolling back the last migration operation") - migrateRollback(currpath, driverStr, connStr) + beeLogger.Log.Info("Rolling back the last migration operation") + MigrateRollback(currpath, driverStr, connStr) case "reset": - logger.Info("Reseting all migrations") - migrateReset(currpath, driverStr, connStr) + beeLogger.Log.Info("Reseting all migrations") + MigrateReset(currpath, driverStr, connStr) case "refresh": - logger.Info("Refreshing all migrations") - migrateRefresh(currpath, driverStr, connStr) + beeLogger.Log.Info("Refreshing all migrations") + MigrateRefresh(currpath, driverStr, connStr) default: - logger.Fatal("Command is missing") + beeLogger.Log.Fatal("Command is missing") } } - logger.Success("Migration successful!") + beeLogger.Log.Success("Migration successful!") return 0 } -// migrateUpdate does the schema update -func migrateUpdate(currpath, driver, connStr string) { - migrate("upgrade", currpath, driver, connStr) -} - -// migrateRollback rolls back the latest migration -func migrateRollback(currpath, driver, connStr string) { - migrate("rollback", currpath, driver, connStr) -} - -// migrateReset rolls back all migrations -func migrateReset(currpath, driver, connStr string) { - migrate("reset", currpath, driver, connStr) -} - -// migrationRefresh rolls back all migrations and start over again -func migrateRefresh(currpath, driver, connStr string) { - migrate("refresh", currpath, driver, connStr) -} - // migrate generates source code, build it, and invoke the binary who does the actual migration func migrate(goal, currpath, driver, connStr string) { dir := path.Join(currpath, "database", "migrations") @@ -153,7 +134,7 @@ func migrate(goal, currpath, driver, connStr string) { // Connect to database db, err := sql.Open(driver, connStr) if err != nil { - logger.Fatalf("Could not connect to database using '%s': %s", connStr, err) + beeLogger.Log.Fatalf("Could not connect to database using '%s': %s", connStr, err) } defer db.Close() @@ -171,44 +152,44 @@ func migrate(goal, currpath, driver, connStr string) { func checkForSchemaUpdateTable(db *sql.DB, driver string) { showTableSQL := showMigrationsTableSQL(driver) if rows, err := db.Query(showTableSQL); err != nil { - logger.Fatalf("Could not show migrations table: %s", err) + beeLogger.Log.Fatalf("Could not show migrations table: %s", err) } else if !rows.Next() { // No migrations table, create new ones createTableSQL := createMigrationsTableSQL(driver) - logger.Infof("Creating 'migrations' table...") + beeLogger.Log.Infof("Creating 'migrations' table...") if _, err := db.Query(createTableSQL); err != nil { - logger.Fatalf("Could not create migrations table: %s", err) + beeLogger.Log.Fatalf("Could not create migrations table: %s", err) } } // Checking that migrations table schema are expected selectTableSQL := selectMigrationsTableSQL(driver) if rows, err := db.Query(selectTableSQL); err != nil { - logger.Fatalf("Could not show columns of migrations table: %s", err) + beeLogger.Log.Fatalf("Could not show columns of migrations table: %s", err) } else { for rows.Next() { var fieldBytes, typeBytes, nullBytes, keyBytes, defaultBytes, extraBytes []byte if err := rows.Scan(&fieldBytes, &typeBytes, &nullBytes, &keyBytes, &defaultBytes, &extraBytes); err != nil { - logger.Fatalf("Could not read column information: %s", err) + beeLogger.Log.Fatalf("Could not read column information: %s", err) } fieldStr, typeStr, nullStr, keyStr, defaultStr, extraStr := string(fieldBytes), string(typeBytes), string(nullBytes), string(keyBytes), string(defaultBytes), string(extraBytes) if fieldStr == "id_migration" { if keyStr != "PRI" || extraStr != "auto_increment" { - logger.Hint("Expecting KEY: PRI, EXTRA: auto_increment") - logger.Fatalf("Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s", keyStr, extraStr) + beeLogger.Log.Hint("Expecting KEY: PRI, EXTRA: auto_increment") + beeLogger.Log.Fatalf("Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s", keyStr, extraStr) } } else if fieldStr == "name" { if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" { - logger.Hint("Expecting TYPE: varchar, NULL: YES") - logger.Fatalf("Column migration.name type mismatch: TYPE: %s, NULL: %s", typeStr, nullStr) + beeLogger.Log.Hint("Expecting TYPE: varchar, NULL: YES") + beeLogger.Log.Fatalf("Column migration.name type mismatch: TYPE: %s, NULL: %s", typeStr, nullStr) } } else if fieldStr == "created_at" { if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" { - logger.Hint("Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP") - logger.Fatalf("Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s", typeStr, defaultStr) + beeLogger.Log.Hint("Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP") + beeLogger.Log.Fatalf("Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s", typeStr, defaultStr) } } } @@ -252,22 +233,22 @@ func selectMigrationsTableSQL(driver string) string { func getLatestMigration(db *sql.DB, goal string) (file string, createdAt int64) { sql := "SELECT name FROM migrations where status = 'update' ORDER BY id_migration DESC LIMIT 1" if rows, err := db.Query(sql); err != nil { - logger.Fatalf("Could not retrieve migrations: %s", err) + beeLogger.Log.Fatalf("Could not retrieve migrations: %s", err) } else { if rows.Next() { if err := rows.Scan(&file); err != nil { - logger.Fatalf("Could not read migrations in database: %s", err) + beeLogger.Log.Fatalf("Could not read migrations in database: %s", err) } createdAtStr := file[len(file)-15:] if t, err := time.Parse("20060102_150405", createdAtStr); err != nil { - logger.Fatalf("Could not parse time: %s", err) + beeLogger.Log.Fatalf("Could not parse time: %s", err) } else { createdAt = t.Unix() } } else { // migration table has no 'update' record, no point rolling back if goal == "rollback" { - logger.Fatal("There is nothing to rollback") + beeLogger.Log.Fatal("There is nothing to rollback") } file, createdAt = "", 0 } @@ -279,7 +260,7 @@ func getLatestMigration(db *sql.DB, goal string) (file string, createdAt int64) func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime int64, latestName string, task string) { changeDir(dir) if f, err := os.OpenFile(source, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil { - logger.Fatalf("Could not create file: %s", err) + beeLogger.Log.Fatalf("Could not create file: %s", err) } else { content := strings.Replace(MigrationMainTPL, "{{DBDriver}}", driver, -1) content = strings.Replace(content, "{{ConnStr}}", connStr, -1) @@ -287,9 +268,9 @@ func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime in content = strings.Replace(content, "{{LatestName}}", latestName, -1) content = strings.Replace(content, "{{Task}}", task, -1) if _, err := f.WriteString(content); err != nil { - logger.Fatalf("Could not write to file: %s", err) + beeLogger.Log.Fatalf("Could not write to file: %s", err) } - CloseFile(f) + utils.CloseFile(f) } } @@ -298,7 +279,7 @@ func buildMigrationBinary(dir, binary string) { changeDir(dir) cmd := exec.Command("go", "build", "-o", binary) if out, err := cmd.CombinedOutput(); err != nil { - logger.Errorf("Could not build migration binary: %s", err) + beeLogger.Log.Errorf("Could not build migration binary: %s", err) formatShellErrOutput(string(out)) removeTempFile(dir, binary) removeTempFile(dir, binary+".go") @@ -312,7 +293,7 @@ func runMigrationBinary(dir, binary string) { cmd := exec.Command("./" + binary) if out, err := cmd.CombinedOutput(); err != nil { formatShellOutput(string(out)) - logger.Errorf("Could not run migration binary: %s", err) + beeLogger.Log.Errorf("Could not run migration binary: %s", err) removeTempFile(dir, binary) removeTempFile(dir, binary+".go") os.Exit(2) @@ -325,7 +306,7 @@ func runMigrationBinary(dir, binary string) { // It exits the system when encouter an error func changeDir(dir string) { if err := os.Chdir(dir); err != nil { - logger.Fatalf("Could not find migration directory: %s", err) + beeLogger.Log.Fatalf("Could not find migration directory: %s", err) } } @@ -333,7 +314,7 @@ func changeDir(dir string) { func removeTempFile(dir, file string) { changeDir(dir) if err := os.Remove(file); err != nil { - logger.Warnf("Could not remove temporary file: %s", err) + beeLogger.Log.Warnf("Could not remove temporary file: %s", err) } } @@ -341,7 +322,7 @@ func removeTempFile(dir, file string) { func formatShellErrOutput(o string) { for _, line := range strings.Split(o, "\n") { if line != "" { - logger.Errorf("|> %s", line) + beeLogger.Log.Errorf("|> %s", line) } } } @@ -350,7 +331,7 @@ func formatShellErrOutput(o string) { func formatShellOutput(o string) { for _, line := range strings.Split(o, "\n") { if line != "" { - logger.Infof("|> %s", line) + beeLogger.Log.Infof("|> %s", line) } } } @@ -421,3 +402,23 @@ CREATE TABLE migrations ( status migrations_status )` ) + +// MigrateUpdate does the schema update +func MigrateUpdate(currpath, driver, connStr string) { + migrate("upgrade", currpath, driver, connStr) +} + +// MigrateRollback rolls back the latest migration +func MigrateRollback(currpath, driver, connStr string) { + migrate("rollback", currpath, driver, connStr) +} + +// MigrateReset rolls back all migrations +func MigrateReset(currpath, driver, connStr string) { + migrate("reset", currpath, driver, connStr) +} + +// migrationRefresh rolls back all migrations and start over again +func MigrateRefresh(currpath, driver, connStr string) { + migrate("refresh", currpath, driver, connStr) +} diff --git a/new.go b/cmd/commands/new/new.go similarity index 97% rename from new.go rename to cmd/commands/new/new.go index 6eb9e73..299f094 100644 --- a/new.go +++ b/cmd/commands/new/new.go @@ -12,16 +12,22 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package new import ( "fmt" "os" path "path/filepath" "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" ) -var cmdNew = &Command{ +var CmdNew = &commands.Command{ UsageLine: "new [appname]", Short: "Creates a Beego application", Long: ` @@ -47,74 +53,8 @@ Creates a Beego application for the given app name in the current directory. └── index.tpl `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: createApp, -} - -func createApp(cmd *Command, args []string) int { - output := cmd.Out() - if len(args) != 1 { - logger.Fatal("Argument [appname] is missing") - } - - apppath, packpath, err := checkEnv(args[0]) - if err != nil { - logger.Fatalf("%s", err) - } - - if isExist(apppath) { - logger.Errorf(bold("Application '%s' already exists"), apppath) - logger.Warn(bold("Do you want to overwrite it? [Yes|No] ")) - if !askForConfirmation() { - os.Exit(2) - } - } - - logger.Info("Creating application...") - - os.MkdirAll(apppath, 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "conf"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "controllers"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "models"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "routers"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "tests"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "static"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "static", "js"), 0755) - WriteToFile(path.Join(apppath, "static", "js", "reload.min.js"), reloadJsClient) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "js")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "static", "css"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "css")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "static", "img"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "img")+string(path.Separator), "\x1b[0m") - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views")+string(path.Separator), "\x1b[0m") - os.Mkdir(path.Join(apppath, "views"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m") - WriteToFile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1)) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "default.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "controllers", "default.go"), controllers) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views", "index.tpl"), "\x1b[0m") - WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packpath, -1)) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packpath, -1)) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1)) - - logger.Success("New application successfully created!") - return 0 + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: CreateApp, } var appconf = `appname = {{.Appname}} @@ -303,3 +243,73 @@ var indextpl = ` var reloadJsClient = `function b(a){var c=new WebSocket(a);c.onclose=function(){setTimeout(function(){b(a)},2E3)};c.onmessage=function(){location.reload()}}try{if(window.WebSocket)try{b("ws://localhost:12450/reload")}catch(a){console.error(a)}else console.log("Your browser does not support WebSockets.")}catch(a){console.error("Exception during connecting to Reload:",a)}; ` + +func init() { + commands.AvailableCommands = append(commands.AvailableCommands, CmdNew) +} + +func CreateApp(cmd *commands.Command, args []string) int { + output := cmd.Out() + if len(args) != 1 { + beeLogger.Log.Fatal("Argument [appname] is missing") + } + + apppath, packpath, err := utils.CheckEnv(args[0]) + if err != nil { + beeLogger.Log.Fatalf("%s", err) + } + + if utils.IsExist(apppath) { + beeLogger.Log.Errorf(colors.Bold("Application '%s' already exists"), apppath) + beeLogger.Log.Warn(colors.Bold("Do you want to overwrite it? [Yes|No] ")) + if !utils.AskForConfirmation() { + os.Exit(2) + } + } + + beeLogger.Log.Info("Creating application...") + + os.MkdirAll(apppath, 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "conf"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "controllers"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "models"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "routers"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "tests"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "static"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "static", "js"), 0755) + utils.WriteToFile(path.Join(apppath, "static", "js", "reload.min.js"), reloadJsClient) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "js")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "static", "css"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "css")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "static", "img"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "img")+string(path.Separator), "\x1b[0m") + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views")+string(path.Separator), "\x1b[0m") + os.Mkdir(path.Join(apppath, "views"), 0755) + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1)) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "default.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "controllers", "default.go"), controllers) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views", "index.tpl"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packpath, -1)) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packpath, -1)) + + fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") + utils.WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1)) + + beeLogger.Log.Success("New application successfully created!") + return 0 +} diff --git a/pack.go b/cmd/commands/pack/pack.go similarity index 83% rename from pack.go rename to cmd/commands/pack/pack.go index c957585..ee7eced 100644 --- a/pack.go +++ b/cmd/commands/pack/pack.go @@ -1,18 +1,4 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main +package pack import ( "archive/tar" @@ -31,9 +17,14 @@ import ( "strings" "syscall" "time" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" ) -var cmdPack = &Command{ +var CmdPack = &commands.Command{ CustomFlags: true, UsageLine: "pack", Short: "Compresses a Beego application into a single file", @@ -43,7 +34,7 @@ var cmdPack = &Command{ {{"Example:"|bold}} $ bee pack -v -ba="-ldflags '-s -w'" `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, Run: packApp, } @@ -52,27 +43,16 @@ var ( excludeP string excludeS string outputP string - excludeR ListOpts + excludeR utils.ListOpts fsym bool ssym bool build bool buildArgs string - buildEnvs ListOpts + buildEnvs utils.ListOpts verbose bool format string ) -type ListOpts []string - -func (opts *ListOpts) String() string { - return fmt.Sprint(*opts) -} - -func (opts *ListOpts) Set(value string) error { - *opts = append(*opts, value) - return nil -} - func init() { fs := flag.NewFlagSet("pack", flag.ContinueOnError) fs.StringVar(&appPath, "p", "", "Set the application path. Defaults to the current path.") @@ -87,7 +67,8 @@ func init() { fs.BoolVar(&fsym, "fs", false, "Tell the command to follow symlinks. Defaults to false.") fs.BoolVar(&ssym, "ss", false, "Tell the command to skip symlinks. Defaults to false.") fs.BoolVar(&verbose, "v", false, "Be more verbose during the operation. Defaults to false.") - cmdPack.Flag = *fs + CmdPack.Flag = *fs + commands.AvailableCommands = append(commands.AvailableCommands, CmdPack) } type walker interface { @@ -115,10 +96,6 @@ type walkFileTree struct { output *io.Writer } -func (wft *walkFileTree) setPrefix(prefix string) { - wft.prefix = prefix -} - func (wft *walkFileTree) isExclude(fPath string) bool { if fPath == "" { return true @@ -316,12 +293,12 @@ func (wft *tarWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) { return false, err } - if isSym == false { + if !isSym { fr, err := os.Open(fpath) if err != nil { return false, err } - defer CloseFile(fr) + defer utils.CloseFile(fr) _, err = io.Copy(tw, fr) if err != nil { return false, err @@ -352,12 +329,12 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) { return false, err } - if isSym == false { + if !isSym { fr, err := os.Open(fpath) if err != nil { return false, err } - defer CloseFile(fr) + defer utils.CloseFile(fr) _, err = io.Copy(w, fr) if err != nil { return false, err @@ -379,10 +356,10 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) { func packDirectory(output io.Writer, excludePrefix []string, excludeSuffix []string, excludeRegexp []*regexp.Regexp, includePath ...string) (err error) { - logger.Infof("Excluding relpath prefix: %s", strings.Join(excludePrefix, ":")) - logger.Infof("Excluding relpath suffix: %s", strings.Join(excludeSuffix, ":")) + beeLogger.Log.Infof("Excluding relpath prefix: %s", strings.Join(excludePrefix, ":")) + beeLogger.Log.Infof("Excluding relpath suffix: %s", strings.Join(excludeSuffix, ":")) if len(excludeRegexp) > 0 { - logger.Infof("Excluding filename regex: `%s`", strings.Join(excludeR, "`, `")) + beeLogger.Log.Infof("Excluding filename regex: `%s`", strings.Join(excludeR, "`, `")) } w, err := os.OpenFile(outputP, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) @@ -437,7 +414,7 @@ func packDirectory(output io.Writer, excludePrefix []string, excludeSuffix []str return } -func packApp(cmd *Command, args []string) int { +func packApp(cmd *commands.Command, args []string) int { output := cmd.Out() curPath, _ := os.Getwd() thePath := "" @@ -454,19 +431,19 @@ func packApp(cmd *Command, args []string) int { } cmd.Flag.Parse(nArgs) - if path.IsAbs(appPath) == false { + if !path.IsAbs(appPath) { appPath = path.Join(curPath, appPath) } thePath, err := path.Abs(appPath) if err != nil { - logger.Fatalf("Wrong application path: %s", thePath) + beeLogger.Log.Fatalf("Wrong application path: %s", thePath) } - if stat, err := os.Stat(thePath); os.IsNotExist(err) || stat.IsDir() == false { - logger.Fatalf("Application path does not exist: %s", thePath) + if stat, err := os.Stat(thePath); os.IsNotExist(err) || !stat.IsDir() { + beeLogger.Log.Fatalf("Application path does not exist: %s", thePath) } - logger.Infof("Packaging application on '%s'...", thePath) + beeLogger.Log.Infof("Packaging application on '%s'...", thePath) appName := path.Base(thePath) @@ -488,12 +465,12 @@ func packApp(cmd *Command, args []string) int { // Remove the tmpdir once bee pack is done err := os.RemoveAll(tmpdir) if err != nil { - logger.Error("Failed to remove the generated temp dir") + beeLogger.Log.Error("Failed to remove the generated temp dir") } }() if build { - logger.Info("Building application...") + beeLogger.Log.Info("Building application...") var envs []string for _, env := range buildEnvs { parts := strings.SplitN(env, "=", 2) @@ -515,7 +492,7 @@ func packApp(cmd *Command, args []string) int { os.Setenv("GOOS", goos) os.Setenv("GOARCH", goarch) - logger.Infof("Using: GOOS=%s GOARCH=%s", goos, goarch) + beeLogger.Log.Infof("Using: GOOS=%s GOARCH=%s", goos, goarch) binPath := path.Join(tmpdir, appName) if goos == "windows" { @@ -538,10 +515,10 @@ func packApp(cmd *Command, args []string) int { execmd.Dir = thePath err = execmd.Run() if err != nil { - logger.Fatal(err.Error()) + beeLogger.Log.Fatal(err.Error()) } - logger.Success("Build Successful!") + beeLogger.Log.Success("Build Successful!") } switch format { @@ -552,14 +529,14 @@ func packApp(cmd *Command, args []string) int { outputN := appName + "." + format - if outputP == "" || path.IsAbs(outputP) == false { + if outputP == "" || !path.IsAbs(outputP) { outputP = path.Join(curPath, outputP) } if _, err := os.Stat(outputP); err != nil { err = os.MkdirAll(outputP, 0755) if err != nil { - logger.Fatal(err.Error()) + beeLogger.Log.Fatal(err.Error()) } } @@ -581,20 +558,20 @@ func packApp(cmd *Command, args []string) int { for _, r := range excludeR { if len(r) > 0 { if re, err := regexp.Compile(r); err != nil { - logger.Fatal(err.Error()) + beeLogger.Log.Fatal(err.Error()) } else { exr = append(exr, re) } } } - logger.Infof("Writing to output: %s", outputP) + beeLogger.Log.Infof("Writing to output: %s", outputP) err = packDirectory(output, exp, exs, exr, tmpdir, thePath) if err != nil { - logger.Fatal(err.Error()) + beeLogger.Log.Fatal(err.Error()) } - logger.Success("Application packed!") + beeLogger.Log.Success("Application packed!") return 0 } diff --git a/cmd/commands/rs/rs.go b/cmd/commands/rs/rs.go new file mode 100644 index 0000000..c520bee --- /dev/null +++ b/cmd/commands/rs/rs.go @@ -0,0 +1,102 @@ +// Copyright 2017 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package rs ... +package rs + +import ( + "fmt" + "os" + "os/exec" + "runtime" + "time" + + "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/config" + "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" +) + +var cmdRs = &commands.Command{ + UsageLine: "rs", + Short: "Run customized scripts", + Long: `Run script allows you to run arbitrary commands using Bee. + Custom commands are provided from the "scripts" object inside bee.json or Beefile. + + To run a custom command, use: {{"$ bee rs mycmd ARGS" | bold}} + {{if len .}} +{{"AVAILABLE SCRIPTS"|headline}}{{range $cmdName, $cmd := .}} + {{$cmdName | bold}} + {{$cmd}}{{end}}{{end}} +`, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: runScript, +} + +func init() { + config.LoadConfig() + cmdRs.Long = utils.TmplToString(cmdRs.Long, config.Conf.Scripts) + commands.AvailableCommands = append(commands.AvailableCommands, cmdRs) +} + +func runScript(cmd *commands.Command, args []string) int { + if len(args) == 0 { + cmd.Usage() + } + + start := time.Now() + script, args := args[0], args[1:] + + if c, exist := config.Conf.Scripts[script]; exist { + command := customCommand{ + Name: script, + Command: c, + Args: args, + } + if err := command.run(); err != nil { + beeLogger.Log.Error(err.Error()) + } + } else { + beeLogger.Log.Errorf("Command '%s' not found in Beefile/bee.json", script) + } + elapsed := time.Since(start) + fmt.Println(colors.GreenBold(fmt.Sprintf("Finished in %s.", elapsed))) + return 0 +} + +type customCommand struct { + Name string + Command string + Args []string +} + +func (c *customCommand) run() error { + beeLogger.Log.Info(colors.GreenBold(fmt.Sprintf("Running '%s'...", c.Name))) + var cmd *exec.Cmd + switch runtime.GOOS { + case "darwin", "linux": + args := append([]string{c.Command}, c.Args...) + cmd = exec.Command("sh", "-c", strings.Join(args, " ")) + case "windows": + args := append([]string{c.Command}, c.Args...) + cmd = exec.Command("cmd", "/C", strings.Join(args, " ")) + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/cmd/commands/run/docs.go b/cmd/commands/run/docs.go new file mode 100644 index 0000000..28979a0 --- /dev/null +++ b/cmd/commands/run/docs.go @@ -0,0 +1,88 @@ +package run + +import ( + "archive/zip" + "io" + "net/http" + "os" + "strings" + + beeLogger "github.com/beego/bee/logger" +) + +var ( + swaggerVersion = "2" + swaggerlink = "https://github.com/beego/swagger/archive/v" + swaggerVersion + ".zip" +) + +func downloadFromURL(url, fileName string) { + var down bool + if fd, err := os.Stat(fileName); err != nil && os.IsNotExist(err) { + down = true + } else if fd.Size() == int64(0) { + down = true + } else { + beeLogger.Log.Infof("'%s' already exists", fileName) + return + } + if down { + beeLogger.Log.Infof("Downloading '%s' to '%s'...", url, fileName) + output, err := os.Create(fileName) + if err != nil { + beeLogger.Log.Errorf("Error while creating '%s': %s", fileName, err) + return + } + defer output.Close() + + response, err := http.Get(url) + if err != nil { + beeLogger.Log.Errorf("Error while downloading '%s': %s", url, err) + return + } + defer response.Body.Close() + + n, err := io.Copy(output, response.Body) + if err != nil { + beeLogger.Log.Errorf("Error while downloading '%s': %s", url, err) + return + } + beeLogger.Log.Successf("%d bytes downloaded!", n) + } +} + +func unzipAndDelete(src string) error { + beeLogger.Log.Infof("Unzipping '%s'...", src) + r, err := zip.OpenReader(src) + if err != nil { + return err + } + defer r.Close() + + rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger") + for _, f := range r.File { + rc, err := f.Open() + if err != nil { + return err + } + defer rc.Close() + + fname := rp.Replace(f.Name) + if f.FileInfo().IsDir() { + os.MkdirAll(fname, f.Mode()) + } else { + f, err := os.OpenFile( + fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer f.Close() + + _, err = io.Copy(f, rc) + if err != nil { + return err + } + } + } + beeLogger.Log.Successf("Done! Deleting '%s'...", src) + return os.RemoveAll(src) +} diff --git a/reload.go b/cmd/commands/run/reload.go similarity index 92% rename from reload.go rename to cmd/commands/run/reload.go index c7d3c0d..4cd731a 100644 --- a/reload.go +++ b/cmd/commands/run/reload.go @@ -11,13 +11,14 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. -package main +package run import ( "bytes" "net/http" "time" + beeLogger "github.com/beego/bee/logger" "github.com/gorilla/websocket" ) @@ -70,7 +71,7 @@ func (c *wsClient) readPump() { _, _, err := c.conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { - logger.Errorf("An error happened when reading from the Websocket client: %v", err) + beeLogger.Log.Errorf("An error happened when reading from the Websocket client: %v", err) } break } @@ -109,7 +110,7 @@ func (c *wsClient) writePump() { n := len(c.send) for i := 0; i < n; i++ { - w.Write(newline) + w.Write([]byte("/n")) w.Write(<-c.send) } @@ -155,13 +156,13 @@ func startReloadServer() { }) go startServer() - logger.Infof("Reload server listening at %s", reloadAddress) + beeLogger.Log.Infof("Reload server listening at %s", reloadAddress) } func startServer() { err := http.ListenAndServe(reloadAddress, nil) if err != nil { - logger.Errorf("Failed to start up the Reload server: %v", err) + beeLogger.Log.Errorf("Failed to start up the Reload server: %v", err) return } } @@ -175,7 +176,7 @@ func sendReload(payload string) { func handleWsRequest(broker *wsBroker, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - logger.Errorf("error while upgrading server connection: %v", err) + beeLogger.Log.Errorf("error while upgrading server connection: %v", err) return } diff --git a/run.go b/cmd/commands/run/run.go similarity index 54% rename from run.go rename to cmd/commands/run/run.go index ba8af0c..6820024 100644 --- a/run.go +++ b/cmd/commands/run/run.go @@ -11,8 +11,7 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. - -package main +package run import ( "io/ioutil" @@ -20,25 +19,31 @@ import ( path "path/filepath" "runtime" "strings" + + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/cmd/commands/version" + "github.com/beego/bee/config" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" ) -var cmdRun = &Command{ - UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-tags=goBuildTags] [-runmode=BEEGO_RUNMODE]", +var CmdRun = &commands.Command{ + UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-ex=extraPackageToWatch] [-tags=goBuildTags] [-runmode=BEEGO_RUNMODE]", Short: "Run the application by starting a local development server", Long: ` Run command will supervise the filesystem of the application for any changes, and recompile/restart it. `, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: runApp, + PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }, + Run: RunApp, } var ( - mainFiles ListOpts - downdoc docValue - gendoc docValue + mainFiles utils.ListOpts + downdoc utils.DocValue + gendoc utils.DocValue // The flags list of the paths excluded from watching - excludedPaths strFlags + excludedPaths utils.StrFlags // Pass through to -tags arg of "go build" buildTags string // Application path @@ -53,65 +58,64 @@ var ( currentGoPath string // Current runmode runmode string + // Extra directories + extraPackages utils.StrFlags ) +var started = make(chan bool) func init() { - cmdRun.Flag.Var(&mainFiles, "main", "Specify main go files.") - cmdRun.Flag.Var(&gendoc, "gendoc", "Enable auto-generate the docs.") - cmdRun.Flag.Var(&downdoc, "downdoc", "Enable auto-download of the swagger file if it does not exist.") - cmdRun.Flag.Var(&excludedPaths, "e", "List of paths to exclude.") - cmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Enable watch vendor folder.") - cmdRun.Flag.StringVar(&buildTags, "tags", "", "Set the build tags. See: https://golang.org/pkg/go/build/") - cmdRun.Flag.StringVar(&runmode, "runmode", "", "Set the Beego run mode.") + CmdRun.Flag.Var(&mainFiles, "main", "Specify main go files.") + CmdRun.Flag.Var(&gendoc, "gendoc", "Enable auto-generate the docs.") + CmdRun.Flag.Var(&downdoc, "downdoc", "Enable auto-download of the swagger file if it does not exist.") + CmdRun.Flag.Var(&excludedPaths, "e", "List of paths to exclude.") + CmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Enable watch vendor folder.") + CmdRun.Flag.StringVar(&buildTags, "tags", "", "Set the build tags. See: https://golang.org/pkg/go/build/") + CmdRun.Flag.StringVar(&runmode, "runmode", "", "Set the Beego run mode.") + CmdRun.Flag.Var(&extraPackages, "ex", "List of extra package to watch.") exit = make(chan bool) + commands.AvailableCommands = append(commands.AvailableCommands, CmdRun) } -func runApp(cmd *Command, args []string) int { +func RunApp(cmd *commands.Command, args []string) int { if len(args) == 0 || args[0] == "watchall" { currpath, _ = os.Getwd() - - if found, _gopath, _ := SearchGOPATHs(currpath); found { + if found, _gopath, _ := utils.SearchGOPATHs(currpath); found { appname = path.Base(currpath) currentGoPath = _gopath } else { - logger.Fatalf("No application '%s' found in your GOPATH", currpath) + beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", currpath) } } else { // Check if passed Bee application path/name exists in the GOPATH(s) - if found, _gopath, _path := SearchGOPATHs(args[0]); found { + if found, _gopath, _path := utils.SearchGOPATHs(args[0]); found { currpath = _path currentGoPath = _gopath appname = path.Base(currpath) } else { - logger.Fatalf("No application '%s' found in your GOPATH", args[0]) + beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", args[0]) } - if strings.HasSuffix(appname, ".go") && isExist(currpath) { - logger.Warnf("The appname is in conflict with file's current path. Do you want to build appname as '%s'", appname) - logger.Info("Do you want to overwrite it? [yes|no] ") - if !askForConfirmation() { + if strings.HasSuffix(appname, ".go") && utils.IsExist(currpath) { + beeLogger.Log.Warnf("The appname is in conflict with file's current path. Do you want to build appname as '%s'", appname) + beeLogger.Log.Info("Do you want to overwrite it? [yes|no] ") + if !utils.AskForConfirmation() { return 0 } } } - logger.Infof("Using '%s' as 'appname'", appname) + beeLogger.Log.Infof("Using '%s' as 'appname'", appname) - logger.Debugf("Current path: %s", __FILE__(), __LINE__(), currpath) + beeLogger.Log.Debugf("Current path: %s", utils.FILE(), utils.LINE(), currpath) if runmode == "prod" || runmode == "dev" { os.Setenv("BEEGO_RUNMODE", runmode) - logger.Infof("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE")) + beeLogger.Log.Infof("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE")) } else if runmode != "" { os.Setenv("BEEGO_RUNMODE", runmode) - logger.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE")) + beeLogger.Log.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE")) } else if os.Getenv("BEEGO_RUNMODE") != "" { - logger.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE")) - } - - err := loadConfig() - if err != nil { - logger.Fatalf("Failed to load configuration: %s", err) + beeLogger.Log.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE")) } var paths []string @@ -119,10 +123,32 @@ func runApp(cmd *Command, args []string) int { // Because monitor files has some issues, we watch current directory // and ignore non-go files. - for _, p := range conf.DirStruct.Others { + for _, p := range config.Conf.DirStruct.Others { paths = append(paths, strings.Replace(p, "$GOPATH", currentGoPath, -1)) } + if len(extraPackages) > 0 { + // get the full path + for _, packagePath := range extraPackages { + if found, _, _fullPath := utils.SearchGOPATHs(packagePath); found { + readAppDirectories(_fullPath, &paths) + } else { + beeLogger.Log.Warnf("No extra package '%s' found in your GOPATH", packagePath) + } + } + // let paths unique + strSet := make(map[string]struct{}) + for _, p := range paths { + strSet[p] = struct{}{} + } + paths = make([]string, len(strSet)) + index := 0 + for i := range strSet { + paths[index] = i + index++ + } + } + files := []string{} for _, arg := range mainFiles { if len(arg) > 0 { @@ -139,7 +165,7 @@ func runApp(cmd *Command, args []string) int { } // Start the Reload server (if enabled) - if conf.EnableReload { + if config.Conf.EnableReload { startReloadServer() } if gendoc == "true" { @@ -151,10 +177,8 @@ func runApp(cmd *Command, args []string) int { } for { - select { - case <-exit: - runtime.Goexit() - } + <-exit + runtime.Goexit() } } @@ -181,16 +205,16 @@ func readAppDirectories(directory string, paths *[]string) { continue } - if fileInfo.IsDir() == true && fileInfo.Name()[0] != '.' { + if fileInfo.IsDir() && fileInfo.Name()[0] != '.' { readAppDirectories(directory+"/"+fileInfo.Name(), paths) continue } - if useDirectory == true { + if useDirectory { continue } - if path.Ext(fileInfo.Name()) == ".go" || (ifStaticFile(fileInfo.Name()) && conf.EnableReload) { + if path.Ext(fileInfo.Name()) == ".go" || (ifStaticFile(fileInfo.Name()) && config.Conf.EnableReload) { *paths = append(*paths, directory) useDirectory = true } @@ -203,16 +227,16 @@ func isExcluded(filePath string) bool { for _, p := range excludedPaths { absP, err := path.Abs(p) if err != nil { - logger.Errorf("Cannot get absolute path of '%s'", p) + beeLogger.Log.Errorf("Cannot get absolute path of '%s'", p) continue } absFilePath, err := path.Abs(filePath) if err != nil { - logger.Errorf("Cannot get absolute path of '%s'", filePath) + beeLogger.Log.Errorf("Cannot get absolute path of '%s'", filePath) break } if strings.HasPrefix(absFilePath, absP) { - logger.Infof("'%s' is not being watched", filePath) + beeLogger.Log.Infof("'%s' is not being watched", filePath) return true } } diff --git a/watch.go b/cmd/commands/run/watch.go similarity index 72% rename from watch.go rename to cmd/commands/run/watch.go index 9b1daa4..7fb2a81 100644 --- a/watch.go +++ b/cmd/commands/run/watch.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package run import ( "bytes" @@ -24,6 +24,10 @@ import ( "sync" "time" + "github.com/beego/bee/config" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" "github.com/fsnotify/fsnotify" ) @@ -46,7 +50,7 @@ var ( func NewWatcher(paths []string, files []string, isgenerate bool) { watcher, err := fsnotify.NewWatcher() if err != nil { - logger.Fatalf("Failed to create watcher: %s", err) + beeLogger.Log.Fatalf("Failed to create watcher: %s", err) } go func() { @@ -55,7 +59,7 @@ func NewWatcher(paths []string, files []string, isgenerate bool) { case e := <-watcher.Events: isBuild := true - if ifStaticFile(e.Name) && conf.EnableReload { + if ifStaticFile(e.Name) && config.Conf.EnableReload { sendReload(e.String()) continue } @@ -69,14 +73,14 @@ func NewWatcher(paths []string, files []string, isgenerate bool) { mt := getFileModTime(e.Name) if t := eventTime[e.Name]; mt == t { - logger.Infof(bold("Skipping: ")+"%s", e.String()) + beeLogger.Log.Hintf(colors.Bold("Skipping: ")+"%s", e.String()) isBuild = false } eventTime[e.Name] = mt if isBuild { - logger.Infof("Event fired: %s", e) + beeLogger.Log.Hintf("Event fired: %s", e) go func() { // Wait 1s before autobuild until there is no file change. scheduleTime = time.Now().Add(1 * time.Second) @@ -85,17 +89,17 @@ func NewWatcher(paths []string, files []string, isgenerate bool) { }() } case err := <-watcher.Errors: - logger.Warnf("Watcher error: %s", err.Error()) // No need to exit here + beeLogger.Log.Warnf("Watcher error: %s", err.Error()) // No need to exit here } } }() - logger.Info("Initializing watcher...") + beeLogger.Log.Info("Initializing watcher...") for _, path := range paths { - logger.Infof(bold("Watching: ")+"%s", path) + beeLogger.Log.Hintf(colors.Bold("Watching: ")+"%s", path) err = watcher.Add(path) if err != nil { - logger.Fatalf("Failed to watch directory: %s", err) + beeLogger.Log.Fatalf("Failed to watch directory: %s", err) } } } @@ -105,14 +109,14 @@ func getFileModTime(path string) int64 { path = strings.Replace(path, "\\", "/", -1) f, err := os.Open(path) if err != nil { - logger.Errorf("Failed to open file on '%s': %s", path, err) + beeLogger.Log.Errorf("Failed to open file on '%s': %s", path, err) return time.Now().Unix() } defer f.Close() fi, err := f.Stat() if err != nil { - logger.Errorf("Failed to get file stats: %s", err) + beeLogger.Log.Errorf("Failed to get file stats: %s", err) return time.Now().Unix() } @@ -127,57 +131,32 @@ func AutoBuild(files []string, isgenerate bool) { os.Chdir(currpath) cmdName := "go" - if conf.Gopm.Enable { - cmdName = "gopm" - } var ( err error stderr bytes.Buffer - stdout bytes.Buffer ) // For applications use full import path like "github.com/.../.." // are able to use "go install" to reduce build time. - if conf.GoInstall { + if config.Conf.GoInstall { icmd := exec.Command(cmdName, "install", "-v") icmd.Stdout = os.Stdout icmd.Stderr = os.Stderr icmd.Env = append(os.Environ(), "GOGC=off") icmd.Run() } - if conf.Gopm.Install { - icmd := exec.Command("go", "list", "./...") - icmd.Stdout = &stdout - icmd.Env = append(os.Environ(), "GOGC=off") - err = icmd.Run() - if err == nil { - list := strings.Split(stdout.String(), "\n")[1:] - for _, pkg := range list { - if len(pkg) == 0 { - continue - } - icmd = exec.Command(cmdName, "install", pkg) - icmd.Stdout = os.Stdout - icmd.Stderr = os.Stderr - icmd.Env = append(os.Environ(), "GOGC=off") - err = icmd.Run() - if err != nil { - break - } - } - } - } if isgenerate { - logger.Info("Generating the docs...") + beeLogger.Log.Info("Generating the docs...") icmd := exec.Command("bee", "generate", "docs") icmd.Env = append(os.Environ(), "GOGC=off") err = icmd.Run() if err != nil { - logger.Errorf("Failed to generate the docs.") + utils.Notify("", "Failed to generate the docs.") + beeLogger.Log.Errorf("Failed to generate the docs.") return } - logger.Success("Docs generated!") + beeLogger.Log.Success("Docs generated!") } if err == nil { @@ -198,12 +177,13 @@ func AutoBuild(files []string, isgenerate bool) { bcmd.Stderr = &stderr err = bcmd.Run() if err != nil { - logger.Errorf("Failed to build the application: %s", stderr.String()) + utils.Notify(stderr.String(), "Build Failed") + beeLogger.Log.Errorf("Failed to build the application: %s", stderr.String()) return } } - logger.Success("Built Successfully!") + beeLogger.Log.Success("Built Successfully!") Restart(appname) } @@ -211,39 +191,39 @@ func AutoBuild(files []string, isgenerate bool) { func Kill() { defer func() { if e := recover(); e != nil { - logger.Infof("Kill recover: %s", e) + beeLogger.Log.Infof("Kill recover: %s", e) } }() if cmd != nil && cmd.Process != nil { err := cmd.Process.Kill() if err != nil { - logger.Errorf("Error while killing cmd process: %s", err) + beeLogger.Log.Errorf("Error while killing cmd process: %s", err) } } } // Restart kills the running command process and starts it again func Restart(appname string) { - logger.Debugf("Kill running process", __FILE__(), __LINE__()) + beeLogger.Log.Debugf("Kill running process", utils.FILE(), utils.LINE()) Kill() go Start(appname) } // Start starts the command process func Start(appname string) { - logger.Infof("Restarting '%s'...", appname) - if strings.Index(appname, "./") == -1 { + beeLogger.Log.Infof("Restarting '%s'...", appname) + if !strings.Contains(appname, "./") { appname = "./" + appname } cmd = exec.Command(appname) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - cmd.Args = append([]string{appname}, conf.CmdArgs...) - cmd.Env = append(os.Environ(), conf.Envs...) + cmd.Args = append([]string{appname}, config.Conf.CmdArgs...) + cmd.Env = append(os.Environ(), config.Conf.Envs...) go cmd.Run() - logger.Successf("'%s' is running...", appname) + beeLogger.Log.Successf("'%s' is running...", appname) started <- true } @@ -262,7 +242,7 @@ func shouldIgnoreFile(filename string) bool { for _, regex := range ignoredFilesRegExps { r, err := regexp.Compile(regex) if err != nil { - logger.Fatalf("Could not compile regular expression: %s", err) + beeLogger.Log.Fatalf("Could not compile regular expression: %s", err) } if r.MatchString(filename) { return true diff --git a/banner.go b/cmd/commands/version/banner.go similarity index 66% rename from banner.go rename to cmd/commands/version/banner.go index fb06316..0ab367d 100644 --- a/banner.go +++ b/cmd/commands/version/banner.go @@ -1,4 +1,4 @@ -package main +package version import ( "io" @@ -6,6 +6,10 @@ import ( "os" "runtime" "text/template" + + "time" + + beeLogger "github.com/beego/bee/logger" ) // RuntimeInfo holds information about the current runtime. @@ -26,12 +30,12 @@ type RuntimeInfo struct { // print the banner in case of error. func InitBanner(out io.Writer, in io.Reader) { if in == nil { - logger.Fatal("The input is nil") + beeLogger.Log.Fatal("The input is nil") } banner, err := ioutil.ReadAll(in) if err != nil { - logger.Fatalf("Error while trying to read the banner: %s", err) + beeLogger.Log.Fatalf("Error while trying to read the banner: %s", err) } show(out, string(banner)) @@ -43,11 +47,11 @@ func show(out io.Writer, content string) { Parse(content) if err != nil { - logger.Fatalf("Cannot parse the banner template: %s", err) + beeLogger.Log.Fatalf("Cannot parse the banner template: %s", err) } err = t.Execute(out, RuntimeInfo{ - getGoVersion(), + GetGoVersion(), runtime.GOOS, runtime.GOARCH, runtime.NumCPU(), @@ -55,7 +59,14 @@ func show(out io.Writer, content string) { runtime.GOROOT(), runtime.Compiler, version, - getBeegoVersion(), + GetBeegoVersion(), }) - MustCheck(err) + if err != nil { + beeLogger.Log.Error(err.Error()) + } +} + +// Now returns the current local time in the specified layout +func Now(layout string) string { + return time.Now().Format(layout) } diff --git a/version.go b/cmd/commands/version/version.go similarity index 75% rename from version.go rename to cmd/commands/version/version.go index 6da9d1d..a1a3050 100644 --- a/version.go +++ b/cmd/commands/version/version.go @@ -1,4 +1,4 @@ -package main +package version import ( "bufio" @@ -14,18 +14,12 @@ import ( "runtime" "strings" + "github.com/beego/bee/cmd/commands" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" "gopkg.in/yaml.v2" ) -var cmdVersion = &Command{ - UsageLine: "version", - Short: "Prints the current Bee version", - Long: ` -Prints the current Bee, Beego and Go version alongside the platform information. -`, - Run: versionCmd, -} - const verboseVersionBanner string = `%s%s______ | ___ \ | |_/ / ___ ___ @@ -52,21 +46,33 @@ const shortVersionBanner = `______ \____/ \___| \___| v{{ .BeeVersion }} ` +var CmdVersion = &commands.Command{ + UsageLine: "version", + Short: "Prints the current Bee version", + Long: ` +Prints the current Bee, Beego and Go version alongside the platform information. +`, + Run: versionCmd, +} var outputFormat string +const version = "1.8.1" + func init() { fs := flag.NewFlagSet("version", flag.ContinueOnError) fs.StringVar(&outputFormat, "o", "", "Set the output format. Either json or yaml.") - cmdVersion.Flag = *fs + CmdVersion.Flag = *fs + commands.AvailableCommands = append(commands.AvailableCommands, CmdVersion) } -func versionCmd(cmd *Command, args []string) int { +func versionCmd(cmd *commands.Command, args []string) int { + cmd.Flag.Parse(args) stdout := cmd.Out() if outputFormat != "" { runtimeInfo := RuntimeInfo{ - getGoVersion(), + GetGoVersion(), runtime.GOOS, runtime.GOARCH, runtime.NumCPU(), @@ -74,20 +80,24 @@ func versionCmd(cmd *Command, args []string) int { runtime.GOROOT(), runtime.Compiler, version, - getBeegoVersion(), + GetBeegoVersion(), } switch outputFormat { case "json": { b, err := json.MarshalIndent(runtimeInfo, "", " ") - MustCheck(err) + if err != nil { + beeLogger.Log.Error(err.Error()) + } fmt.Println(string(b)) return 0 } case "yaml": { b, err := yaml.Marshal(&runtimeInfo) - MustCheck(err) + if err != nil { + beeLogger.Log.Error(err.Error()) + } fmt.Println(string(b)) return 0 } @@ -102,18 +112,18 @@ func versionCmd(cmd *Command, args []string) int { // ShowShortVersionBanner prints the short version banner. func ShowShortVersionBanner() { - output := NewColorWriter(os.Stdout) - InitBanner(output, bytes.NewBufferString(MagentaBold(shortVersionBanner))) + output := colors.NewColorWriter(os.Stdout) + InitBanner(output, bytes.NewBufferString(colors.MagentaBold(shortVersionBanner))) } -func getBeegoVersion() string { +func GetBeegoVersion() string { gopath := os.Getenv("GOPATH") re, err := regexp.Compile(`VERSION = "([0-9.]+)"`) if err != nil { return "" } if gopath == "" { - err = fmt.Errorf("You need to set GOPATH environment variable") + beeLogger.Log.Error("You need to set GOPATH environment variable") return "" } wgopath := path.SplitList(gopath) @@ -125,11 +135,11 @@ func getBeegoVersion() string { if os.IsNotExist(err) { continue } - logger.Error("Error while getting stats of 'beego.go'") + beeLogger.Log.Error("Error while getting stats of 'beego.go'") } fd, err := os.Open(filename) if err != nil { - logger.Error("Error while reading 'beego.go'") + beeLogger.Log.Error("Error while reading 'beego.go'") continue } reader := bufio.NewReader(fd) @@ -152,14 +162,14 @@ func getBeegoVersion() string { return "Beego is not installed. Please do consider installing it first: https://github.com/astaxie/beego" } -func getGoVersion() string { +func GetGoVersion() string { var ( cmdOut []byte err error ) if cmdOut, err = exec.Command("go", "version").Output(); err != nil { - logger.Fatalf("There was an error running 'go version' command: %s", err) + beeLogger.Log.Fatalf("There was an error running 'go version' command: %s", err) } return strings.Split(string(cmdOut), " ")[2] } diff --git a/code.go b/code.go deleted file mode 100644 index 335b021..0000000 --- a/code.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2011 Gary Burd -// Copyright 2013 Unknown -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main - -import ( - "go/ast" - "go/printer" - "go/scanner" - "go/token" - "math" - "strconv" -) - -const ( - notPredeclared = iota - predeclaredType - predeclaredConstant - predeclaredFunction -) - -// predeclared represents the set of all predeclared identifiers. -var predeclared = map[string]int{ - "bool": predeclaredType, - "byte": predeclaredType, - "complex128": predeclaredType, - "complex64": predeclaredType, - "error": predeclaredType, - "float32": predeclaredType, - "float64": predeclaredType, - "int16": predeclaredType, - "int32": predeclaredType, - "int64": predeclaredType, - "int8": predeclaredType, - "int": predeclaredType, - "rune": predeclaredType, - "string": predeclaredType, - "uint16": predeclaredType, - "uint32": predeclaredType, - "uint64": predeclaredType, - "uint8": predeclaredType, - "uint": predeclaredType, - "uintptr": predeclaredType, - - "true": predeclaredConstant, - "false": predeclaredConstant, - "iota": predeclaredConstant, - "nil": predeclaredConstant, - - "append": predeclaredFunction, - "cap": predeclaredFunction, - "close": predeclaredFunction, - "complex": predeclaredFunction, - "copy": predeclaredFunction, - "delete": predeclaredFunction, - "imag": predeclaredFunction, - "len": predeclaredFunction, - "make": predeclaredFunction, - "new": predeclaredFunction, - "panic": predeclaredFunction, - "print": predeclaredFunction, - "println": predeclaredFunction, - "real": predeclaredFunction, - "recover": predeclaredFunction, -} - -const ( - ExportLinkAnnotation AnnotationKind = iota - AnchorAnnotation - CommentAnnotation - PackageLinkAnnotation - BuiltinAnnotation -) - -// annotationVisitor collects annotations. -type annotationVisitor struct { - annotations []Annotation -} - -func (v *annotationVisitor) add(kind AnnotationKind, importPath string) { - v.annotations = append(v.annotations, Annotation{Kind: kind, ImportPath: importPath}) -} - -func (v *annotationVisitor) ignoreName() { - v.add(-1, "") -} - -func (v *annotationVisitor) Visit(n ast.Node) ast.Visitor { - switch n := n.(type) { - case *ast.TypeSpec: - v.ignoreName() - ast.Walk(v, n.Type) - case *ast.FuncDecl: - if n.Recv != nil { - ast.Walk(v, n.Recv) - } - v.ignoreName() - ast.Walk(v, n.Type) - case *ast.Field: - for range n.Names { - v.ignoreName() - } - ast.Walk(v, n.Type) - case *ast.ValueSpec: - for range n.Names { - v.add(AnchorAnnotation, "") - } - if n.Type != nil { - ast.Walk(v, n.Type) - } - for _, x := range n.Values { - ast.Walk(v, x) - } - case *ast.Ident: - switch { - case n.Obj == nil && predeclared[n.Name] != notPredeclared: - v.add(BuiltinAnnotation, "") - case n.Obj != nil && ast.IsExported(n.Name): - v.add(ExportLinkAnnotation, "") - default: - v.ignoreName() - } - case *ast.SelectorExpr: - if x, _ := n.X.(*ast.Ident); x != nil { - if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg { - if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil { - if path, err := strconv.Unquote(spec.Path.Value); err == nil { - v.add(PackageLinkAnnotation, path) - if path == "C" { - v.ignoreName() - } else { - v.add(ExportLinkAnnotation, path) - } - return nil - } - } - } - } - ast.Walk(v, n.X) - v.ignoreName() - default: - return v - } - return nil -} - -func printDecl(decl ast.Node, fset *token.FileSet, buf []byte) (Code, []byte) { - v := &annotationVisitor{} - ast.Walk(v, decl) - - buf = buf[:0] - err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(sliceWriter{&buf}, fset, decl) - if err != nil { - return Code{Text: err.Error()}, buf - } - - var annotations []Annotation - var s scanner.Scanner - fset = token.NewFileSet() - file := fset.AddFile("", fset.Base(), len(buf)) - s.Init(file, buf, nil, scanner.ScanComments) -loop: - for { - pos, tok, lit := s.Scan() - switch tok { - case token.EOF: - break loop - case token.COMMENT: - p := file.Offset(pos) - e := p + len(lit) - if p > math.MaxInt16 || e > math.MaxInt16 { - break loop - } - annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)}) - case token.IDENT: - if len(v.annotations) == 0 { - // Oops! - break loop - } - annotation := v.annotations[0] - v.annotations = v.annotations[1:] - if annotation.Kind == -1 { - continue - } - p := file.Offset(pos) - e := p + len(lit) - if p > math.MaxInt16 || e > math.MaxInt16 { - break loop - } - annotation.Pos = int16(p) - annotation.End = int16(e) - if len(annotations) > 0 && annotation.Kind == ExportLinkAnnotation { - prev := annotations[len(annotations)-1] - if prev.Kind == PackageLinkAnnotation && - prev.ImportPath == annotation.ImportPath && - prev.End+1 == annotation.Pos { - // merge with previous - annotation.Pos = prev.Pos - annotations[len(annotations)-1] = annotation - continue loop - } - } - annotations = append(annotations, annotation) - } - } - return Code{Text: string(buf), Annotations: annotations}, buf -} - -type AnnotationKind int16 - -type Annotation struct { - Pos, End int16 - Kind AnnotationKind - ImportPath string -} - -type Code struct { - Text string - Annotations []Annotation -} - -func commentAnnotations(src string) []Annotation { - var annotations []Annotation - var s scanner.Scanner - fset := token.NewFileSet() - file := fset.AddFile("", fset.Base(), len(src)) - s.Init(file, []byte(src), nil, scanner.ScanComments) - for { - pos, tok, lit := s.Scan() - switch tok { - case token.EOF: - return annotations - case token.COMMENT: - p := file.Offset(pos) - e := p + len(lit) - if p > math.MaxInt16 || e > math.MaxInt16 { - return annotations - } - annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)}) - } - } -} - -type sliceWriter struct{ p *[]byte } - -func (w sliceWriter) Write(p []byte) (int, error) { - *w.p = append(*w.p, p...) - return len(p), nil -} diff --git a/conf.go b/conf.go deleted file mode 100644 index e352f84..0000000 --- a/conf.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main - -import ( - "encoding/json" - "io/ioutil" - "os" - - "io" - "path/filepath" - - "gopkg.in/yaml.v2" -) - -const confVer = 0 - -var defaultConf = `{ - "version": 0, - "gopm": { - "enable": false, - "install": false - }, - "go_install": true, - "watch_ext": [], - "dir_structure": { - "watch_all": false, - "controllers": "", - "models": "", - "others": [] - }, - "cmd_args": [], - "envs": [], - "database": { - "driver": "mysql" - }, - "enable_reload": false -} -` -var conf struct { - Version int - // gopm support - Gopm struct { - Enable bool - Install bool - } - // Indicates whether execute "go install" before "go build". - GoInstall bool `json:"go_install" yaml:"go_install"` - WatchExt []string `json:"watch_ext" yaml:"watch_ext"` - DirStruct struct { - WatchAll bool `json:"watch_all" yaml:"watch_all"` - Controllers string - Models string - Others []string // Other directories. - } `json:"dir_structure" yaml:"dir_structure"` - CmdArgs []string `json:"cmd_args" yaml:"cmd_args"` - Envs []string - Bale struct { - Import string - Dirs []string - IngExt []string `json:"ignore_ext" yaml:"ignore_ext"` - } - Database struct { - Driver string - Conn string - } - EnableReload bool `json:"enable_reload" yaml:"enable_reload"` -} - -// loadConfig loads customized configuration. -func loadConfig() (err error) { - err = filepath.Walk(".", func(path string, fileInfo os.FileInfo, err error) error { - if err != nil { - return nil - } - - if fileInfo.IsDir() { - return nil - } - - if fileInfo.Name() == "bee.json" { - logger.Info("Loading configuration from 'bee.json'...") - err = parseJSON(path, &conf) - if err != nil { - logger.Errorf("Failed to parse JSON file: %s", err) - return err - } - return io.EOF - } - - if fileInfo.Name() == "Beefile" { - logger.Info("Loading configuration from 'Beefile'...") - err = parseYAML(path, &conf) - if err != nil { - logger.Errorf("Failed to parse YAML file: %s", err) - return err - } - return io.EOF - } - return nil - }) - - // In case no configuration file found or an error different than io.EOF, - // fallback to default configuration - if err != io.EOF { - logger.Info("Loading default configuration...") - err = json.Unmarshal([]byte(defaultConf), &conf) - if err != nil { - return - } - } - - // No need to return io.EOF error - err = nil - - // Check format version - if conf.Version != confVer { - logger.Warn("Your configuration file is outdated. Please do consider updating it.") - logger.Hint("Check the latest version of bee's configuration file.") - } - - // Set variables - if len(conf.DirStruct.Controllers) == 0 { - conf.DirStruct.Controllers = "controllers" - } - if len(conf.DirStruct.Models) == 0 { - conf.DirStruct.Models = "models" - } - - // Append watch exts - watchExts = append(watchExts, conf.WatchExt...) - return -} - -func parseJSON(path string, v interface{}) error { - var ( - data []byte - err error - ) - data, err = ioutil.ReadFile(path) - if err != nil { - return err - } - err = json.Unmarshal(data, v) - if err != nil { - return err - } - return nil -} - -func parseYAML(path string, v interface{}) error { - var ( - data []byte - err error - ) - data, err = ioutil.ReadFile(path) - if err != nil { - return err - } - err = yaml.Unmarshal(data, v) - if err != nil { - return err - } - return nil -} diff --git a/config/conf.go b/config/conf.go new file mode 100644 index 0000000..eebbce2 --- /dev/null +++ b/config/conf.go @@ -0,0 +1,159 @@ +// Copyright 2013 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +package config + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + + beeLogger "github.com/beego/bee/logger" + "gopkg.in/yaml.v2" +) + +const confVer = 0 + +var Conf = struct { + Version int + GoInstall bool `json:"go_install" yaml:"go_install"` // Indicates whether execute "go install" before "go build". + DirStruct dirStruct `json:"dir_structure" yaml:"dir_structure"` + CmdArgs []string `json:"cmd_args" yaml:"cmd_args"` + Envs []string + Bale bale + Database database + EnableReload bool `json:"enable_reload" yaml:"enable_reload"` + EnableNotification bool `json:"enable_notification" yaml:"enable_notification"` + Scripts map[string]string `json:"scripts" yaml:"scripts"` +}{ + GoInstall: true, + DirStruct: dirStruct{ + Others: []string{}, + }, + CmdArgs: []string{}, + Envs: []string{}, + Bale: bale{ + Dirs: []string{}, + IngExt: []string{}, + }, + Database: database{ + Driver: "mysql", + }, + EnableNotification: true, + Scripts: map[string]string{}, +} + +// dirStruct describes the application's directory structure +type dirStruct struct { + WatchAll bool `json:"watch_all" yaml:"watch_all"` + Controllers string + Models string + Others []string // Other directories +} + +// bale +type bale struct { + Import string + Dirs []string + IngExt []string `json:"ignore_ext" yaml:"ignore_ext"` +} + +// database holds the database connection information +type database struct { + Driver string + Conn string +} + +// LoadConfig loads the bee tool configuration. +// It looks for Beefile or bee.json in the current path, +// and falls back to default configuration in case not found. +func LoadConfig() { + currentPath, err := os.Getwd() + if err != nil { + beeLogger.Log.Error(err.Error()) + } + + dir, err := os.Open(currentPath) + if err != nil { + beeLogger.Log.Error(err.Error()) + } + defer dir.Close() + + files, err := dir.Readdir(-1) + if err != nil { + beeLogger.Log.Error(err.Error()) + } + + for _, file := range files { + switch file.Name() { + case "bee.json": + { + err = parseJSON(filepath.Join(currentPath, file.Name()), &Conf) + if err != nil { + beeLogger.Log.Errorf("Failed to parse JSON file: %s", err) + } + break + } + case "Beefile": + { + err = parseYAML(filepath.Join(currentPath, file.Name()), &Conf) + if err != nil { + beeLogger.Log.Errorf("Failed to parse YAML file: %s", err) + } + break + } + } + } + + // Check format version + if Conf.Version != confVer { + beeLogger.Log.Warn("Your configuration file is outdated. Please do consider updating it.") + beeLogger.Log.Hint("Check the latest version of bee's configuration file.") + } + + // Set variables + if len(Conf.DirStruct.Controllers) == 0 { + Conf.DirStruct.Controllers = "controllers" + } + + if len(Conf.DirStruct.Models) == 0 { + Conf.DirStruct.Models = "models" + } +} + +func parseJSON(path string, v interface{}) error { + var ( + data []byte + err error + ) + data, err = ioutil.ReadFile(path) + if err != nil { + return err + } + err = json.Unmarshal(data, v) + return err +} + +func parseYAML(path string, v interface{}) error { + var ( + data []byte + err error + ) + data, err = ioutil.ReadFile(path) + if err != nil { + return err + } + err = yaml.Unmarshal(data, v) + return err +} diff --git a/g.go b/g.go deleted file mode 100644 index 8c133d9..0000000 --- a/g.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main - -import ( - "os" - "strings" -) - -var cmdGenerate = &Command{ - UsageLine: "generate [command]", - Short: "Source code generator", - Long: `▶ {{"To scaffold out your entire application:"|bold}} - - $ bee generate scaffold [scaffoldname] [-fields="title:string,body:text"] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] - - ▶ {{"To generate a Model based on fields:"|bold}} - - $ bee generate model [modelname] [-fields="name:type"] - - ▶ {{"To generate a controller:"|bold}} - - $ bee generate controller [controllerfile] - - ▶ {{"To generate a CRUD view:"|bold}} - - $ bee generate view [viewpath] - - ▶ {{"To generate a migration file for making database schema updates:"|bold}} - - $ bee generate migration [migrationfile] [-fields="name:type"] - - ▶ {{"To generate swagger doc file:"|bold}} - - $ bee generate docs - - ▶ {{"To generate a test case:"|bold}} - - $ bee generate test [routerfile] - - ▶ {{"To generate appcode based on an existing database:"|bold}} - - $ bee generate appcode [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3] -`, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: generateCode, -} - -var driver docValue -var conn docValue -var level docValue -var tables docValue -var fields docValue - -func init() { - cmdGenerate.Flag.Var(&tables, "tables", "List of table names separated by a comma.") - cmdGenerate.Flag.Var(&driver, "driver", "Database driver. Either mysql, postgres or sqlite.") - cmdGenerate.Flag.Var(&conn, "conn", "Connection string used by the driver to connect to a database instance.") - cmdGenerate.Flag.Var(&level, "level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.") - cmdGenerate.Flag.Var(&fields, "fields", "List of table fields.") -} - -func generateCode(cmd *Command, args []string) int { - currpath, _ := os.Getwd() - if len(args) < 1 { - logger.Fatal("Command is missing") - } - - gps := GetGOPATHs() - if len(gps) == 0 { - logger.Fatal("GOPATH environment variable is not set or empty") - } - - gopath := gps[0] - - logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath) - - gcmd := args[0] - switch gcmd { - case "scaffold": - if len(args) < 2 { - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - // Load the configuration - err := loadConfig() - if err != nil { - logger.Fatalf("Failed to load configuration: %s", err) - } - cmd.Flag.Parse(args[2:]) - if driver == "" { - driver = docValue(conf.Database.Driver) - if driver == "" { - driver = "mysql" - } - } - if conn == "" { - conn = docValue(conf.Database.Conn) - if conn == "" { - conn = "root:@tcp(127.0.0.1:3306)/test" - } - } - if fields == "" { - logger.Hint("fields option should not be empty, i.e. -fields=\"title:string,body:text\"") - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - sname := args[1] - generateScaffold(sname, fields.String(), currpath, driver.String(), conn.String()) - case "docs": - generateDocs(currpath) - case "appcode": - // Load the configuration - err := loadConfig() - if err != nil { - logger.Fatalf("Failed to load configuration: %s", err) - } - cmd.Flag.Parse(args[1:]) - if driver == "" { - driver = docValue(conf.Database.Driver) - if driver == "" { - driver = "mysql" - } - } - if conn == "" { - conn = docValue(conf.Database.Conn) - if conn == "" { - if driver == "mysql" { - conn = "root:@tcp(127.0.0.1:3306)/test" - } else if driver == "postgres" { - conn = "postgres://postgres:postgres@127.0.0.1:5432/postgres" - } - } - } - if level == "" { - level = "3" - } - logger.Infof("Using '%s' as 'driver'", driver) - logger.Infof("Using '%s' as 'conn'", conn) - logger.Infof("Using '%s' as 'tables'", tables) - logger.Infof("Using '%s' as 'level'", level) - generateAppcode(driver.String(), conn.String(), level.String(), tables.String(), currpath) - case "migration": - if len(args) < 2 { - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - cmd.Flag.Parse(args[2:]) - mname := args[1] - - logger.Infof("Using '%s' as migration name", mname) - - upsql := "" - downsql := "" - if fields != "" { - dbMigrator := newDBDriver() - upsql = dbMigrator.generateCreateUp(mname) - downsql = dbMigrator.generateCreateDown(mname) - } - generateMigration(mname, upsql, downsql, currpath) - case "controller": - if len(args) == 2 { - cname := args[1] - generateController(cname, currpath) - } else { - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - case "model": - if len(args) < 2 { - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - cmd.Flag.Parse(args[2:]) - if fields == "" { - logger.Hint("fields option should not be empty, i.e. -fields=\"title:string,body:text\"") - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - sname := args[1] - generateModel(sname, fields.String(), currpath) - case "view": - if len(args) == 2 { - cname := args[1] - generateView(cname, currpath) - } else { - logger.Fatal("Wrong number of arguments. Run: bee help generate") - } - default: - logger.Fatal("Command is missing") - } - logger.Successf("%s successfully generated!", strings.Title(gcmd)) - return 0 -} diff --git a/g_scaffold.go b/g_scaffold.go deleted file mode 100644 index dd43425..0000000 --- a/g_scaffold.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import "strings" - -func generateScaffold(sname, fields, currpath, driver, conn string) { - logger.Infof("Do you want to create a '%s' model? [Yes|No] ", sname) - - // Generate the model - if askForConfirmation() { - generateModel(sname, fields, currpath) - } - - // Generate the controller - logger.Infof("Do you want to create a '%s' controller? [Yes|No] ", sname) - if askForConfirmation() { - generateController(sname, currpath) - } - - // Generate the views - logger.Infof("Do you want to create views for this '%s' resource? [Yes|No] ", sname) - if askForConfirmation() { - generateView(sname, currpath) - } - - // Generate a migration - logger.Infof("Do you want to create a '%s' migration and schema for this resource? [Yes|No] ", sname) - if askForConfirmation() { - upsql := "" - downsql := "" - if fields != "" { - dbMigrator := newDBDriver() - upsql = dbMigrator.generateCreateUp(sname) - downsql = dbMigrator.generateCreateDown(sname) - //todo remove - //if driver == "" { - // downsql = strings.Replace(downsql, "`", "", -1) - //} - } - generateMigration(sname, upsql, downsql, currpath) - } - - // Run the migration - logger.Infof("Do you want to migrate the database? [Yes|No] ") - if askForConfirmation() { - migrateUpdate(currpath, driver, conn) - } - logger.Successf("All done! Don't forget to add beego.Router(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname)) -} diff --git a/generate/g.go b/generate/g.go new file mode 100644 index 0000000..e4260b2 --- /dev/null +++ b/generate/g.go @@ -0,0 +1,23 @@ +// Copyright 2013 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package generate + +import "github.com/beego/bee/utils" + +var SQLDriver utils.DocValue +var SQLConn utils.DocValue +var Level utils.DocValue +var Tables utils.DocValue +var Fields utils.DocValue diff --git a/g_appcode.go b/generate/g_appcode.go similarity index 89% rename from g_appcode.go rename to generate/g_appcode.go index e20cc63..c774689 100644 --- a/g_appcode.go +++ b/generate/g_appcode.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package generate import ( "database/sql" @@ -23,6 +23,9 @@ import ( "regexp" "strings" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" ) @@ -183,7 +186,7 @@ type OrmTag struct { // String returns the source code string for the Table struct func (tb *Table) String() string { - rv := fmt.Sprintf("type %s struct {\n", camelCase(tb.Name)) + rv := fmt.Sprintf("type %s struct {\n", utils.CamelCase(tb.Name)) for _, v := range tb.Columns { rv += v.String() + "\n" } @@ -255,7 +258,7 @@ func (tag *OrmTag) String() string { return fmt.Sprintf("`orm:\"%s\"`", strings.Join(ormOptions, ";")) } -func generateAppcode(driver, connStr, level, tables, currpath string) { +func GenerateAppcode(driver, connStr, level, tables, currpath string) { var mode byte switch level { case "1": @@ -265,7 +268,7 @@ func generateAppcode(driver, connStr, level, tables, currpath string) { case "3": mode = OModel | OController | ORouter default: - logger.Fatal("Invalid level value. Must be either \"1\", \"2\", or \"3\"") + beeLogger.Log.Fatal("Invalid level value. Must be either \"1\", \"2\", or \"3\"") } var selectedTables map[string]bool if tables != "" { @@ -278,9 +281,9 @@ func generateAppcode(driver, connStr, level, tables, currpath string) { case "mysql": case "postgres": case "sqlite": - logger.Fatal("Generating app code from SQLite database is not supported yet.") + beeLogger.Log.Fatal("Generating app code from SQLite database is not supported yet.") default: - logger.Fatal("Unknown database driver. Must be either \"mysql\", \"postgres\" or \"sqlite\"") + beeLogger.Log.Fatal("Unknown database driver. Must be either \"mysql\", \"postgres\" or \"sqlite\"") } gen(driver, connStr, mode, selectedTables, currpath) } @@ -290,11 +293,11 @@ func generateAppcode(driver, connStr, level, tables, currpath string) { func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, apppath string) { db, err := sql.Open(dbms, connStr) if err != nil { - logger.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err) + beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err) } defer db.Close() if trans, ok := dbDriver[dbms]; ok { - logger.Info("Analyzing database tables...") + beeLogger.Log.Info("Analyzing database tables...") tableNames := trans.GetTableNames(db) tables := getTableObjects(tableNames, db, trans) mvcPath := new(MvcPath) @@ -305,7 +308,7 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, ap pkgPath := getPackagePath(apppath) writeSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames) } else { - logger.Fatalf("Generating app code from '%s' database is not supported yet.", dbms) + beeLogger.Log.Fatalf("Generating app code from '%s' database is not supported yet.", dbms) } } @@ -313,13 +316,13 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, ap func (*MysqlDB) GetTableNames(db *sql.DB) (tables []string) { rows, err := db.Query("SHOW TABLES") if err != nil { - logger.Fatalf("Could not show tables: %s", err) + beeLogger.Log.Fatalf("Could not show tables: %s", err) } defer rows.Close() for rows.Next() { var name string if err := rows.Scan(&name); err != nil { - logger.Fatalf("Could not show tables: %s", err) + beeLogger.Log.Fatalf("Could not show tables: %s", err) } tables = append(tables, name) } @@ -362,12 +365,12 @@ func (*MysqlDB) GetConstraints(db *sql.DB, table *Table, blackList map[string]bo c.table_schema = database() AND c.table_name = ? AND u.table_schema = database() AND u.table_name = ?`, table.Name, table.Name) // u.position_in_unique_constraint, if err != nil { - logger.Fatal("Could not query INFORMATION_SCHEMA for PK/UK/FK information") + beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for PK/UK/FK information") } for rows.Next() { var constraintTypeBytes, columnNameBytes, refTableSchemaBytes, refTableNameBytes, refColumnNameBytes, refOrdinalPosBytes []byte if err := rows.Scan(&constraintTypeBytes, &columnNameBytes, &refTableSchemaBytes, &refTableNameBytes, &refColumnNameBytes, &refOrdinalPosBytes); err != nil { - logger.Fatal("Could not read INFORMATION_SCHEMA for PK/UK/FK information") + beeLogger.Log.Fatal("Could not read INFORMATION_SCHEMA for PK/UK/FK information") } constraintType, columnName, refTableSchema, refTableName, refColumnName, refOrdinalPos := string(constraintTypeBytes), string(columnNameBytes), string(refTableSchemaBytes), @@ -407,7 +410,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin table_schema = database() AND table_name = ?`, table.Name) if err != nil { - logger.Fatalf("Could not query the database: %s", err) + beeLogger.Log.Fatalf("Could not query the database: %s", err) } defer colDefRows.Close() @@ -415,17 +418,17 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin // datatype as bytes so that SQL values can be retrieved var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil { - logger.Fatal("Could not query INFORMATION_SCHEMA for column information") + beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for column information") } colName, dataType, columnType, isNullable, columnDefault, extra := string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes) // create a column col := new(Column) - col.Name = camelCase(colName) + col.Name = utils.CamelCase(colName) col.Type, err = mysqlDB.GetGoDataType(dataType) if err != nil { - logger.Fatalf("%s", err) + beeLogger.Log.Fatalf("%s", err) } // Tag info @@ -449,8 +452,8 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin if isFk && !isBl { tag.RelFk = true refStructName := fkCol.RefTable - col.Name = camelCase(colName) - col.Type = "*" + camelCase(refStructName) + col.Name = utils.CamelCase(colName) + col.Type = "*" + utils.CamelCase(refStructName) } else { // if the name of column is Id, and it's not primary key if colName == "id" { @@ -464,7 +467,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin if sign == "unsigned" && extra != "auto_increment" { col.Type, err = mysqlDB.GetGoDataType(dataType + " " + sign) if err != nil { - logger.Fatalf("%s", err) + beeLogger.Log.Fatalf("%s", err) } } } @@ -516,14 +519,14 @@ func (*PostgresDB) GetTableNames(db *sql.DB) (tables []string) { table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')`) if err != nil { - logger.Fatalf("Could not show tables: %s", err) + beeLogger.Log.Fatalf("Could not show tables: %s", err) } defer rows.Close() for rows.Next() { var name string if err := rows.Scan(&name); err != nil { - logger.Fatalf("Could not show tables: %s", err) + beeLogger.Log.Fatalf("Could not show tables: %s", err) } tables = append(tables, name) } @@ -553,13 +556,13 @@ func (*PostgresDB) GetConstraints(db *sql.DB, table *Table, blackList map[string AND u.table_name = $2`, table.Name, table.Name) // u.position_in_unique_constraint, if err != nil { - logger.Fatalf("Could not query INFORMATION_SCHEMA for PK/UK/FK information: %s", err) + beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for PK/UK/FK information: %s", err) } for rows.Next() { var constraintTypeBytes, columnNameBytes, refTableSchemaBytes, refTableNameBytes, refColumnNameBytes, refOrdinalPosBytes []byte if err := rows.Scan(&constraintTypeBytes, &columnNameBytes, &refTableSchemaBytes, &refTableNameBytes, &refColumnNameBytes, &refOrdinalPosBytes); err != nil { - logger.Fatalf("Could not read INFORMATION_SCHEMA for PK/UK/FK information: %s", err) + beeLogger.Log.Fatalf("Could not read INFORMATION_SCHEMA for PK/UK/FK information: %s", err) } constraintType, columnName, refTableSchema, refTableName, refColumnName, refOrdinalPos := string(constraintTypeBytes), string(columnNameBytes), string(refTableSchemaBytes), @@ -609,7 +612,7 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map AND table_name = $1`, table.Name) if err != nil { - logger.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err) + beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err) } defer colDefRows.Close() @@ -617,16 +620,16 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map // datatype as bytes so that SQL values can be retrieved var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil { - logger.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err) + beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err) } colName, dataType, columnType, isNullable, columnDefault, extra := string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes) // Create a column col := new(Column) - col.Name = camelCase(colName) + col.Name = utils.CamelCase(colName) col.Type, err = postgresDB.GetGoDataType(dataType) if err != nil { - logger.Fatalf("%s", err) + beeLogger.Log.Fatalf("%s", err) } // Tag info @@ -650,8 +653,8 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map if isFk && !isBl { tag.RelFk = true refStructName := fkCol.RefTable - col.Name = camelCase(colName) - col.Type = "*" + camelCase(refStructName) + col.Name = utils.CamelCase(colName) + col.Type = "*" + utils.CamelCase(refStructName) } else { // if the name of column is Id, and it's not primary key if colName == "id" { @@ -716,22 +719,22 @@ func createPaths(mode byte, paths *MvcPath) { // Newly geneated files will be inside these folders. func writeSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) { if (OModel & mode) == OModel { - logger.Info("Creating model files...") + beeLogger.Log.Info("Creating model files...") writeModelFiles(tables, paths.ModelPath, selectedTables) } if (OController & mode) == OController { - logger.Info("Creating controller files...") + beeLogger.Log.Info("Creating controller files...") writeControllerFiles(tables, paths.ControllerPath, selectedTables, pkgPath) } if (ORouter & mode) == ORouter { - logger.Info("Creating router files...") + beeLogger.Log.Info("Creating router files...") writeRouterFile(tables, paths.RouterPath, selectedTables, pkgPath) } } // writeModelFiles generates model files func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) { - w := NewColorWriter(os.Stdout) + w := colors.NewColorWriter(os.Stdout) for _, tb := range tables { // if selectedTables map is not nil and this table is not selected, ignore it @@ -744,22 +747,22 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo fpath := path.Join(mPath, filename+".go") var f *os.File var err error - if isExist(fpath) { - logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) - if askForConfirmation() { + if utils.IsExist(fpath) { + beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) + if utils.AskForConfirmation() { f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) continue } } else { - logger.Warnf("Skipped create file '%s'", fpath) + beeLogger.Log.Warnf("Skipped create file '%s'", fpath) continue } } else { f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) continue } } @@ -770,7 +773,7 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo template = ModelTPL } fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1) - fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1) + fileStr = strings.Replace(fileStr, "{{modelName}}", utils.CamelCase(tb.Name), -1) fileStr = strings.Replace(fileStr, "{{tableName}}", tb.Name, -1) // If table contains time field, import time.Time package @@ -783,17 +786,17 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1) fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1) if _, err := f.WriteString(fileStr); err != nil { - logger.Fatalf("Could not write model file to '%s': %s", fpath, err) + beeLogger.Log.Fatalf("Could not write model file to '%s': %s", fpath, err) } - CloseFile(f) + utils.CloseFile(f) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) } } // writeControllerFiles generates controller files func writeControllerFiles(tables []*Table, cPath string, selectedTables map[string]bool, pkgPath string) { - w := NewColorWriter(os.Stdout) + w := colors.NewColorWriter(os.Stdout) for _, tb := range tables { // If selectedTables map is not nil and this table is not selected, ignore it @@ -809,39 +812,39 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri fpath := path.Join(cPath, filename+".go") var f *os.File var err error - if isExist(fpath) { - logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) - if askForConfirmation() { + if utils.IsExist(fpath) { + beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) + if utils.AskForConfirmation() { f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) continue } } else { - logger.Warnf("Skipped create file '%s'", fpath) + beeLogger.Log.Warnf("Skipped create file '%s'", fpath) continue } } else { f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) continue } } - fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", camelCase(tb.Name), -1) + fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", utils.CamelCase(tb.Name), -1) fileStr = strings.Replace(fileStr, "{{pkgPath}}", pkgPath, -1) if _, err := f.WriteString(fileStr); err != nil { - logger.Fatalf("Could not write controller file to '%s': %s", fpath, err) + beeLogger.Log.Fatalf("Could not write controller file to '%s': %s", fpath, err) } - CloseFile(f) + utils.CloseFile(f) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) } } // writeRouterFile generates router file func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bool, pkgPath string) { - w := NewColorWriter(os.Stdout) + w := colors.NewColorWriter(os.Stdout) var nameSpaces []string for _, tb := range tables { @@ -856,7 +859,7 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo } // Add namespaces nameSpace := strings.Replace(NamespaceTPL, "{{nameSpace}}", tb.Name, -1) - nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1) + nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", utils.CamelCase(tb.Name), -1) nameSpaces = append(nameSpaces, nameSpace) } // Add export controller @@ -865,31 +868,31 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo routerStr = strings.Replace(routerStr, "{{pkgPath}}", pkgPath, 1) var f *os.File var err error - if isExist(fpath) { - logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) - if askForConfirmation() { + if utils.IsExist(fpath) { + beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) + if utils.AskForConfirmation() { f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) return } } else { - logger.Warnf("Skipped create file '%s'", fpath) + beeLogger.Log.Warnf("Skipped create file '%s'", fpath) return } } else { f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) return } } if _, err := f.WriteString(routerStr); err != nil { - logger.Fatalf("Could not write router file to '%s': %s", fpath, err) + beeLogger.Log.Fatalf("Could not write router file to '%s': %s", fpath, err) } - CloseFile(f) + utils.CloseFile(f) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) } func isSQLTemporalType(t string) bool { @@ -952,10 +955,10 @@ func getFileName(tbName string) (filename string) { func getPackagePath(curpath string) (packpath string) { gopath := os.Getenv("GOPATH") if gopath == "" { - logger.Fatal("GOPATH environment variable is not set or empty") + beeLogger.Log.Fatal("GOPATH environment variable is not set or empty") } - logger.Debugf("GOPATH: %s", __FILE__(), __LINE__(), gopath) + beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath) appsrcpath := "" haspath := false @@ -964,7 +967,7 @@ func getPackagePath(curpath string) (packpath string) { for _, wg := range wgopath { wg, _ = filepath.EvalSymlinks(path.Join(wg, "src")) - if filepath.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { + if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { haspath = true appsrcpath = wg break @@ -972,11 +975,11 @@ func getPackagePath(curpath string) (packpath string) { } if !haspath { - logger.Fatalf("Cannot generate application code outside of GOPATH '%s'", gopath) + beeLogger.Log.Fatalf("Cannot generate application code outside of GOPATH '%s'", gopath) } if curpath == appsrcpath { - logger.Fatal("Cannot generate application code outside of application path") + beeLogger.Log.Fatal("Cannot generate application code outside of application path") } packpath = strings.Join(strings.Split(curpath[len(appsrcpath)+1:], string(filepath.Separator)), "/") diff --git a/g_controllers.go b/generate/g_controllers.go similarity index 93% rename from g_controllers.go rename to generate/g_controllers.go index a85f3df..d05d04a 100644 --- a/g_controllers.go +++ b/generate/g_controllers.go @@ -12,17 +12,21 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package generate import ( "fmt" "os" "path" "strings" + + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" ) -func generateController(cname, currpath string) { - w := NewColorWriter(os.Stdout) +func GenerateController(cname, currpath string) { + w := colors.NewColorWriter(os.Stdout) p, f := path.Split(cname) controllerName := strings.Title(f) @@ -33,26 +37,26 @@ func generateController(cname, currpath string) { packageName = p[i+1 : len(p)-1] } - logger.Infof("Using '%s' as controller name", controllerName) - logger.Infof("Using '%s' as package name", packageName) + beeLogger.Log.Infof("Using '%s' as controller name", controllerName) + beeLogger.Log.Infof("Using '%s' as package name", packageName) fp := path.Join(currpath, "controllers", p) if _, err := os.Stat(fp); os.IsNotExist(err) { // Create the controller's directory if err := os.MkdirAll(fp, 0777); err != nil { - logger.Fatalf("Could not create controllers directory: %s", err) + beeLogger.Log.Fatalf("Could not create controllers directory: %s", err) } } fpath := path.Join(fp, strings.ToLower(controllerName)+".go") if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) + defer utils.CloseFile(f) modelPath := path.Join(currpath, "models", strings.ToLower(controllerName)+".go") var content string if _, err := os.Stat(modelPath); err == nil { - logger.Infof("Using matching model '%s'", controllerName) + beeLogger.Log.Infof("Using matching model '%s'", controllerName) content = strings.Replace(controllerModelTpl, "{{packageName}}", packageName, -1) pkgPath := getPackagePath(currpath) content = strings.Replace(content, "{{pkgPath}}", pkgPath, -1) @@ -64,10 +68,10 @@ func generateController(cname, currpath string) { f.WriteString(content) // Run 'gofmt' on the generated source code - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") } else { - logger.Fatalf("Could not create controller file: %s", err) + beeLogger.Log.Fatalf("Could not create controller file: %s", err) } } diff --git a/g_hproseappcode.go b/generate/g_hproseappcode.go similarity index 58% rename from g_hproseappcode.go rename to generate/g_hproseappcode.go index 3ce52ae..f73d6ff 100644 --- a/g_hproseappcode.go +++ b/generate/g_hproseappcode.go @@ -15,7 +15,7 @@ * * \**********************************************************/ -package main +package generate import ( "database/sql" @@ -24,11 +24,256 @@ import ( "path" "strings" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" ) -func generateHproseAppcode(driver, connStr, level, tables, currpath string) { +var Hproseconf = `appname = {{.Appname}} +httpport = 8080 +runmode = dev +autorender = false +copyrequestbody = true +EnableDocs = true +` +var HproseMaingo = `package main + +import ( + "fmt" + "reflect" + + "{{.Appname}}/models" + "github.com/hprose/hprose-golang/rpc" + + "github.com/astaxie/beego" +) + +func logInvokeHandler( + name string, + args []reflect.Value, + context rpc.Context, + next rpc.NextInvokeHandler) (results []reflect.Value, err error) { + fmt.Printf("%s(%v) = ", name, args) + results, err = next(name, args, context) + fmt.Printf("%v %v\r\n", results, err) + return +} + +func main() { + // Create WebSocketServer + // service := rpc.NewWebSocketService() + + // Create Http Server + service := rpc.NewHTTPService() + + // Use Logger Middleware + service.AddInvokeHandler(logInvokeHandler) + + // Publish Functions + service.AddFunction("AddOne", models.AddOne) + service.AddFunction("GetOne", models.GetOne) + + // Start Service + beego.Handler("/", service) + beego.Run() +} +` + +var HproseMainconngo = `package main + +import ( + "fmt" + "reflect" + + "{{.Appname}}/models" + "github.com/hprose/hprose-golang/rpc" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/orm" + {{.DriverPkg}} +) + +func init() { + orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}") +} + +func logInvokeHandler( + name string, + args []reflect.Value, + context rpc.Context, + next rpc.NextInvokeHandler) (results []reflect.Value, err error) { + fmt.Printf("%s(%v) = ", name, args) + results, err = next(name, args, context) + fmt.Printf("%v %v\r\n", results, err) + return +} + +func main() { + // Create WebSocketServer + // service := rpc.NewWebSocketService() + + // Create Http Server + service := rpc.NewHTTPService() + + // Use Logger Middleware + service.AddInvokeHandler(logInvokeHandler) + + {{HproseFunctionList}} + + // Start Service + beego.Handler("/", service) + beego.Run() +} + +` + +var HproseModels = `package models + +import ( + "errors" + "strconv" + "time" +) + +var ( + Objects map[string]*Object +) + +type Object struct { + ObjectId string + Score int64 + PlayerName string +} + +func init() { + Objects = make(map[string]*Object) + Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} + Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} +} + +func AddOne(object Object) (ObjectId string) { + object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) + Objects[object.ObjectId] = &object + return object.ObjectId +} + +func GetOne(ObjectId string) (object *Object, err error) { + if v, ok := Objects[ObjectId]; ok { + return v, nil + } + return nil, errors.New("ObjectId Not Exist") +} + +func GetAll() map[string]*Object { + return Objects +} + +func Update(ObjectId string, Score int64) (err error) { + if v, ok := Objects[ObjectId]; ok { + v.Score = Score + return nil + } + return errors.New("ObjectId Not Exist") +} + +func Delete(ObjectId string) { + delete(Objects, ObjectId) +} + +` + +var HproseModels2 = `package models + +import ( + "errors" + "strconv" + "time" +) + +var ( + UserList map[string]*User +) + +func init() { + UserList = make(map[string]*User) + u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}} + UserList["user_11111"] = &u +} + +type User struct { + Id string + Username string + Password string + Profile Profile +} + +type Profile struct { + Gender string + Age int + Address string + Email string +} + +func AddUser(u User) string { + u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10) + UserList[u.Id] = &u + return u.Id +} + +func GetUser(uid string) (u *User, err error) { + if u, ok := UserList[uid]; ok { + return u, nil + } + return nil, errors.New("User not exists") +} + +func GetAllUsers() map[string]*User { + return UserList +} + +func UpdateUser(uid string, uu *User) (a *User, err error) { + if u, ok := UserList[uid]; ok { + if uu.Username != "" { + u.Username = uu.Username + } + if uu.Password != "" { + u.Password = uu.Password + } + if uu.Profile.Age != 0 { + u.Profile.Age = uu.Profile.Age + } + if uu.Profile.Address != "" { + u.Profile.Address = uu.Profile.Address + } + if uu.Profile.Gender != "" { + u.Profile.Gender = uu.Profile.Gender + } + if uu.Profile.Email != "" { + u.Profile.Email = uu.Profile.Email + } + return u, nil + } + return nil, errors.New("User Not Exist") +} + +func Login(username, password string) bool { + for _, u := range UserList { + if u.Username == username && u.Password == password { + return true + } + } + return false +} + +func DeleteUser(uid string) { + delete(UserList, uid) +} +` +var HproseAddFunctions = []string{} + +func GenerateHproseAppcode(driver, connStr, level, tables, currpath string) { var mode byte switch level { case "1": @@ -38,7 +283,7 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) { case "3": mode = OModel | OController | ORouter default: - logger.Fatal("Invalid 'level' option. Level must be either \"1\", \"2\" or \"3\"") + beeLogger.Log.Fatal("Invalid 'level' option. Level must be either \"1\", \"2\" or \"3\"") } var selectedTables map[string]bool if tables != "" { @@ -51,9 +296,9 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) { case "mysql": case "postgres": case "sqlite": - logger.Fatal("Generating app code from SQLite database is not supported yet") + beeLogger.Log.Fatal("Generating app code from SQLite database is not supported yet") default: - logger.Fatalf("Unknown database driver '%s'. Driver must be one of mysql, postgres or sqlite", driver) + beeLogger.Log.Fatalf("Unknown database driver '%s'. Driver must be one of mysql, postgres or sqlite", driver) } genHprose(driver, connStr, mode, selectedTables, currpath) } @@ -63,11 +308,11 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) { func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bool, currpath string) { db, err := sql.Open(dbms, connStr) if err != nil { - logger.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err) + beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err) } defer db.Close() if trans, ok := dbDriver[dbms]; ok { - logger.Info("Analyzing database tables...") + beeLogger.Log.Info("Analyzing database tables...") tableNames := trans.GetTableNames(db) tables := getTableObjects(tableNames, db, trans) mvcPath := new(MvcPath) @@ -76,7 +321,7 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo pkgPath := getPackagePath(currpath) writeHproseSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames) } else { - logger.Fatalf("Generating app code from '%s' database is not supported yet", dbms) + beeLogger.Log.Fatalf("Generating app code from '%s' database is not supported yet", dbms) } } @@ -85,14 +330,14 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo // Newly geneated files will be inside these folders. func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) { if (OModel & mode) == OModel { - logger.Info("Creating model files...") + beeLogger.Log.Info("Creating model files...") writeHproseModelFiles(tables, paths.ModelPath, selectedTables) } } // writeHproseModelFiles generates model files func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) { - w := NewColorWriter(os.Stdout) + w := colors.NewColorWriter(os.Stdout) for _, tb := range tables { // if selectedTables map is not nil and this table is not selected, ignore it @@ -105,22 +350,22 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str fpath := path.Join(mPath, filename+".go") var f *os.File var err error - if isExist(fpath) { - logger.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) - if askForConfirmation() { + if utils.IsExist(fpath) { + beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath) + if utils.AskForConfirmation() { f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) continue } } else { - logger.Warnf("Skipped create file '%s'", fpath) + beeLogger.Log.Warnf("Skipped create file '%s'", fpath) continue } } else { f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666) if err != nil { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) continue } } @@ -129,10 +374,10 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str template = HproseStructModelTPL } else { template = HproseModelTPL - hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", camelCase(tb.Name), -1)) + HproseAddFunctions = append(HproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", utils.CamelCase(tb.Name), -1)) } fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1) - fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1) + fileStr = strings.Replace(fileStr, "{{modelName}}", utils.CamelCase(tb.Name), -1) // if table contains time field, import time.Time package timePkg := "" importTimePkg := "" @@ -143,11 +388,11 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1) fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1) if _, err := f.WriteString(fileStr); err != nil { - logger.Fatalf("Could not write model file to '%s'", fpath) + beeLogger.Log.Fatalf("Could not write model file to '%s'", fpath) } - CloseFile(f) + utils.CloseFile(f) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) } } diff --git a/g_migration.go b/generate/g_migration.go similarity index 76% rename from g_migration.go rename to generate/g_migration.go index 8ab3f1f..56ec063 100644 --- a/g_migration.go +++ b/generate/g_migration.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package generate import ( "fmt" @@ -20,6 +20,10 @@ import ( "path" "strings" "time" + + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" ) const ( @@ -29,18 +33,18 @@ const ( ) type DBDriver interface { - generateCreateUp(tableName string) string - generateCreateDown(tableName string) string + GenerateCreateUp(tableName string) string + GenerateCreateDown(tableName string) string } type mysqlDriver struct{} -func (m mysqlDriver) generateCreateUp(tableName string) string { - upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");` +func (m mysqlDriver) GenerateCreateUp(tableName string) string { + upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(Fields.String()) + `)");` return upsql } -func (m mysqlDriver) generateCreateDown(tableName string) string { +func (m mysqlDriver) GenerateCreateDown(tableName string) string { downsql := `m.SQL("DROP TABLE ` + "`" + tableName + "`" + `")` return downsql } @@ -51,21 +55,21 @@ func (m mysqlDriver) generateSQLFromFields(fields string) string { for i, v := range fds { kv := strings.SplitN(v, ":", 2) if len(kv) != 2 { - logger.Error("Fields format is wrong. Should be: key:type,key:type " + v) + beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v) return "" } typ, tag := m.getSQLType(kv[1]) if typ == "" { - logger.Error("Fields format is wrong. Should be: key:type,key:type " + v) + beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v) return "" } if i == 0 && strings.ToLower(kv[0]) != "id" { sql += "`id` int(11) NOT NULL AUTO_INCREMENT," tags = tags + "PRIMARY KEY (`id`)," } - sql += "`" + snakeString(kv[0]) + "` " + typ + "," + sql += "`" + utils.SnakeString(kv[0]) + "` " + typ + "," if tag != "" { - tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + "," + tags = tags + fmt.Sprintf(tag, "`"+utils.SnakeString(kv[0])+"`") + "," } } sql = strings.TrimRight(sql+tags, ",") @@ -104,12 +108,12 @@ func (m mysqlDriver) getSQLType(ktype string) (tp, tag string) { type postgresqlDriver struct{} -func (m postgresqlDriver) generateCreateUp(tableName string) string { - upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");` +func (m postgresqlDriver) GenerateCreateUp(tableName string) string { + upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(Fields.String()) + `)");` return upsql } -func (m postgresqlDriver) generateCreateDown(tableName string) string { +func (m postgresqlDriver) GenerateCreateDown(tableName string) string { downsql := `m.SQL("DROP TABLE ` + tableName + `")` return downsql } @@ -120,20 +124,20 @@ func (m postgresqlDriver) generateSQLFromFields(fields string) string { for i, v := range fds { kv := strings.SplitN(v, ":", 2) if len(kv) != 2 { - logger.Error("Fields format is wrong. Should be: key:type,key:type " + v) + beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v) return "" } typ, tag := m.getSQLType(kv[1]) if typ == "" { - logger.Error("Fields format is wrong. Should be: key:type,key:type " + v) + beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v) return "" } if i == 0 && strings.ToLower(kv[0]) != "id" { sql += "id serial primary key," } - sql += snakeString(kv[0]) + " " + typ + "," + sql += utils.SnakeString(kv[0]) + " " + typ + "," if tag != "" { - tags = tags + fmt.Sprintf(tag, snakeString(kv[0])) + "," + tags = tags + fmt.Sprintf(tag, utils.SnakeString(kv[0])) + "," } } if tags != "" { @@ -170,14 +174,14 @@ func (m postgresqlDriver) getSQLType(ktype string) (tp, tag string) { return "", "" } -func newDBDriver() DBDriver { - switch driver { +func NewDBDriver() DBDriver { + switch SQLDriver { case "mysql": return mysqlDriver{} case "postgres": return postgresqlDriver{} default: - logger.Fatal("Driver not supported") + beeLogger.Log.Fatal("Driver not supported") return nil } } @@ -185,30 +189,30 @@ func newDBDriver() DBDriver { // generateMigration generates migration file template for database schema update. // The generated file template consists of an up() method for updating schema and // a down() method for reverting the update. -func generateMigration(mname, upsql, downsql, curpath string) { - w := NewColorWriter(os.Stdout) +func GenerateMigration(mname, upsql, downsql, curpath string) { + w := colors.NewColorWriter(os.Stdout) migrationFilePath := path.Join(curpath, DBPath, MPath) if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) { // create migrations directory if err := os.MkdirAll(migrationFilePath, 0777); err != nil { - logger.Fatalf("Could not create migration directory: %s", err) + beeLogger.Log.Fatalf("Could not create migration directory: %s", err) } } // create file today := time.Now().Format(MDateFormat) fpath := path.Join(migrationFilePath, fmt.Sprintf("%s_%s.go", today, mname)) if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) - content := strings.Replace(MigrationTPL, "{{StructName}}", camelCase(mname)+"_"+today, -1) + defer utils.CloseFile(f) + content := strings.Replace(MigrationTPL, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1) content = strings.Replace(content, "{{CurrTime}}", today, -1) content = strings.Replace(content, "{{UpSQL}}", upsql, -1) content = strings.Replace(content, "{{DownSQL}}", downsql, -1) f.WriteString(content) // Run 'gofmt' on the generated source code - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") } else { - logger.Fatalf("Could not create migration file: %s", err) + beeLogger.Log.Fatalf("Could not create migration file: %s", err) } } diff --git a/g_model.go b/generate/g_model.go similarity index 91% rename from g_model.go rename to generate/g_model.go index fc94309..e9b917c 100644 --- a/g_model.go +++ b/generate/g_model.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package generate import ( "errors" @@ -20,10 +20,14 @@ import ( "os" "path" "strings" + + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" ) -func generateModel(mname, fields, currpath string) { - w := NewColorWriter(os.Stdout) +func GenerateModel(mname, fields, currpath string) { + w := colors.NewColorWriter(os.Stdout) p, f := path.Split(mname) modelName := strings.Title(f) @@ -35,23 +39,23 @@ func generateModel(mname, fields, currpath string) { modelStruct, hastime, err := getStruct(modelName, fields) if err != nil { - logger.Fatalf("Could not generate the model struct: %s", err) + beeLogger.Log.Fatalf("Could not generate the model struct: %s", err) } - logger.Infof("Using '%s' as model name", modelName) - logger.Infof("Using '%s' as package name", packageName) + beeLogger.Log.Infof("Using '%s' as model name", modelName) + beeLogger.Log.Infof("Using '%s' as package name", packageName) fp := path.Join(currpath, "models", p) if _, err := os.Stat(fp); os.IsNotExist(err) { // Create the model's directory if err := os.MkdirAll(fp, 0777); err != nil { - logger.Fatalf("Could not create the model directory: %s", err) + beeLogger.Log.Fatalf("Could not create the model directory: %s", err) } } fpath := path.Join(fp, strings.ToLower(modelName)+".go") if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) + defer utils.CloseFile(f) content := strings.Replace(modelTpl, "{{packageName}}", packageName, -1) content = strings.Replace(content, "{{modelName}}", modelName, -1) content = strings.Replace(content, "{{modelStruct}}", modelStruct, -1) @@ -62,10 +66,10 @@ func generateModel(mname, fields, currpath string) { } f.WriteString(content) // Run 'gofmt' on the generated source code - formatSourceCode(fpath) + utils.FormatSourceCode(fpath) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") } else { - logger.Fatalf("Could not create model file: %s", err) + beeLogger.Log.Fatalf("Could not create model file: %s", err) } } @@ -95,7 +99,7 @@ func getStruct(structname, fields string) (string, bool, error) { if hastimeinner { hastime = true } - structStr = structStr + camelString(kv[0]) + " " + typ + " " + tag + "\n" + structStr = structStr + utils.CamelString(kv[0]) + " " + typ + " " + tag + "\n" } structStr += "}\n" return structStr, hastime, nil diff --git a/generate/g_scaffold.go b/generate/g_scaffold.go new file mode 100644 index 0000000..6991d26 --- /dev/null +++ b/generate/g_scaffold.go @@ -0,0 +1,50 @@ +package generate + +import ( + "strings" + + "github.com/beego/bee/cmd/commands/migrate" + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/utils" +) + +func GenerateScaffold(sname, fields, currpath, driver, conn string) { + beeLogger.Log.Infof("Do you want to create a '%s' model? [Yes|No] ", sname) + + // Generate the model + if utils.AskForConfirmation() { + GenerateModel(sname, fields, currpath) + } + + // Generate the controller + beeLogger.Log.Infof("Do you want to create a '%s' controller? [Yes|No] ", sname) + if utils.AskForConfirmation() { + GenerateController(sname, currpath) + } + + // Generate the views + beeLogger.Log.Infof("Do you want to create views for this '%s' resource? [Yes|No] ", sname) + if utils.AskForConfirmation() { + GenerateView(sname, currpath) + } + + // Generate a migration + beeLogger.Log.Infof("Do you want to create a '%s' migration and schema for this resource? [Yes|No] ", sname) + if utils.AskForConfirmation() { + upsql := "" + downsql := "" + if fields != "" { + dbMigrator := NewDBDriver() + upsql = dbMigrator.GenerateCreateUp(sname) + downsql = dbMigrator.GenerateCreateDown(sname) + } + GenerateMigration(sname, upsql, downsql, currpath) + } + + // Run the migration + beeLogger.Log.Infof("Do you want to migrate the database? [Yes|No] ") + if utils.AskForConfirmation() { + migrate.MigrateUpdate(currpath, driver, conn) + } + beeLogger.Log.Successf("All done! Don't forget to add beego.Router(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname)) +} diff --git a/g_views.go b/generate/g_views.go similarity index 72% rename from g_views.go rename to generate/g_views.go index aa7815e..95d99bd 100644 --- a/g_views.go +++ b/generate/g_views.go @@ -12,60 +12,64 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package generate import ( "fmt" "os" "path" + + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" + "github.com/beego/bee/utils" ) // recipe // admin/recipe -func generateView(viewpath, currpath string) { - w := NewColorWriter(os.Stdout) +func GenerateView(viewpath, currpath string) { + w := colors.NewColorWriter(os.Stdout) - logger.Info("Generating view...") + beeLogger.Log.Info("Generating view...") absViewPath := path.Join(currpath, "views", viewpath) err := os.MkdirAll(absViewPath, os.ModePerm) if err != nil { - logger.Fatalf("Could not create '%s' view: %s", viewpath, err) + beeLogger.Log.Fatalf("Could not create '%s' view: %s", viewpath, err) } cfile := path.Join(absViewPath, "index.tpl") if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) + defer utils.CloseFile(f) f.WriteString(cfile) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m") } else { - logger.Fatalf("Could not create view file: %s", err) + beeLogger.Log.Fatalf("Could not create view file: %s", err) } cfile = path.Join(absViewPath, "show.tpl") if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) + defer utils.CloseFile(f) f.WriteString(cfile) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m") } else { - logger.Fatalf("Could not create view file: %s", err) + beeLogger.Log.Fatalf("Could not create view file: %s", err) } cfile = path.Join(absViewPath, "create.tpl") if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) + defer utils.CloseFile(f) f.WriteString(cfile) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m") } else { - logger.Fatalf("Could not create view file: %s", err) + beeLogger.Log.Fatalf("Could not create view file: %s", err) } cfile = path.Join(absViewPath, "edit.tpl") if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { - defer CloseFile(f) + defer utils.CloseFile(f) f.WriteString(cfile) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m") } else { - logger.Fatalf("Could not create view file: %s", err) + beeLogger.Log.Fatalf("Could not create view file: %s", err) } } diff --git a/g_docs.go b/generate/swaggergen/g_docs.go similarity index 94% rename from g_docs.go rename to generate/swaggergen/g_docs.go index 23e3ed5..3063487 100644 --- a/g_docs.go +++ b/generate/swaggergen/g_docs.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package swaggergen import ( "encoding/json" @@ -35,6 +35,7 @@ import ( "github.com/astaxie/beego/swagger" "github.com/astaxie/beego/utils" + beeLogger "github.com/beego/bee/logger" ) const ( @@ -74,7 +75,7 @@ var basicTypes = map[string]string{ "byte": "string:byte", "rune": "string:byte", // builtin golang objects - "time.Time": "string:string", + "time.Time": "string:string", } var stdlibObject = map[string]string{ @@ -90,7 +91,7 @@ func init() { astPkgs = map[string]*ast.Package{} } -func parsePackagesFromDir(dirpath string) { +func ParsePackagesFromDir(dirpath string) { c := make(chan error) go func() { @@ -116,7 +117,7 @@ func parsePackagesFromDir(dirpath string) { }() for err := range c { - logger.Warnf("%s", err) + beeLogger.Log.Warnf("%s", err) } } @@ -137,12 +138,12 @@ func parsePackageFromDir(path string) error { return nil } -func generateDocs(curpath string) { +func GenerateDocs(curpath string) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, path.Join(curpath, "routers", "router.go"), nil, parser.ParseComments) if err != nil { - logger.Fatalf("Error while parsing router.go: %s", err) + beeLogger.Log.Fatalf("Error while parsing router.go: %s", err) } rootapi.Infos = swagger.Information{} @@ -251,6 +252,9 @@ func generateDocs(curpath string) { } os.Mkdir(path.Join(curpath, "swagger"), 0755) fd, err := os.Create(path.Join(curpath, "swagger", "swagger.json")) + if err != nil { + panic(err) + } fdyml, err := os.Create(path.Join(curpath, "swagger", "swagger.yml")) if err != nil { panic(err) @@ -348,7 +352,7 @@ func analyseControllerPkg(localName, pkgpath string) { } gopath := os.Getenv("GOPATH") if gopath == "" { - logger.Fatal("GOPATH environment variable is not set or empty") + beeLogger.Log.Fatal("GOPATH environment variable is not set or empty") } pkgRealpath := "" @@ -366,7 +370,7 @@ func analyseControllerPkg(localName, pkgpath string) { } pkgCache[pkgpath] = struct{}{} } else { - logger.Fatalf("Package '%s' does not exist in the GOPATH", pkgpath) + beeLogger.Log.Fatalf("Package '%s' does not exist in the GOPATH", pkgpath) } fileSet := token.NewFileSet() @@ -375,7 +379,7 @@ func analyseControllerPkg(localName, pkgpath string) { return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") }, parser.ParseComments) if err != nil { - logger.Fatalf("Error while parsing dir at '%s': %s", pkgpath, err) + beeLogger.Log.Fatalf("Error while parsing dir at '%s': %s", pkgpath, err) } for _, pkg := range astPkgs { for _, fl := range pkg.Files { @@ -413,7 +417,7 @@ func isSystemPackage(pkgpath string) bool { goroot = runtime.GOROOT() } if goroot == "" { - logger.Fatalf("GOROOT environment variable is not set or empty") + beeLogger.Log.Fatalf("GOROOT environment variable is not set or empty") } wg, _ := filepath.EvalSymlinks(filepath.Join(goroot, "src", "pkg", pkgpath)) @@ -423,11 +427,7 @@ func isSystemPackage(pkgpath string) bool { //TODO(zh):support go1.4 wg, _ = filepath.EvalSymlinks(filepath.Join(goroot, "src", pkgpath)) - if utils.FileExists(wg) { - return true - } - - return false + return utils.FileExists(wg) } func peekNextSplitString(ss string) (s string, spacePos int) { @@ -481,7 +481,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat ss = strings.TrimSpace(ss[pos:]) schemaName, pos := peekNextSplitString(ss) if schemaName == "" { - logger.Fatalf("[%s.%s] Schema must follow {object} or {array}", controllerName, funcName) + beeLogger.Log.Fatalf("[%s.%s] Schema must follow {object} or {array}", controllerName, funcName) } if strings.HasPrefix(schemaName, "[]") { schemaName = schemaName[2:] @@ -496,7 +496,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat m, mod, realTypes := getModel(schemaName) schema.Ref = "#/definitions/" + m if _, ok := modelsList[pkgpath+controllerName]; !ok { - modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0) + modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema) } modelsList[pkgpath+controllerName][schemaName] = mod appendModels(pkgpath, controllerName, realTypes) @@ -518,7 +518,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat para := swagger.Parameter{} p := getparams(strings.TrimSpace(t[len("@Param "):])) if len(p) < 4 { - logger.Fatal(controllerName + "_" + funcName + "'s comments @Param should have at least 4 params") + beeLogger.Log.Fatal(controllerName + "_" + funcName + "'s comments @Param should have at least 4 params") } para.Name = p[0] switch p[1] { @@ -533,7 +533,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat case "body": break default: - logger.Warnf("[%s.%s] Unknown param location: %s. Possible values are `query`, `header`, `path`, `formData` or `body`.\n", controllerName, funcName, p[1]) + beeLogger.Log.Warnf("[%s.%s] Unknown param location: %s. Possible values are `query`, `header`, `path`, `formData` or `body`.\n", controllerName, funcName, p[1]) } para.In = p[1] pp := strings.Split(p[2], ".") @@ -544,7 +544,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat Ref: "#/definitions/" + m, } if _, ok := modelsList[pkgpath+controllerName]; !ok { - modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0) + modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema) } modelsList[pkgpath+controllerName][typ] = mod appendModels(pkgpath, controllerName, realTypes) @@ -564,7 +564,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat paraType = typeFormat[0] paraFormat = typeFormat[1] } else { - logger.Warnf("[%s.%s] Unknown param type: %s\n", controllerName, funcName, typ) + beeLogger.Log.Warnf("[%s.%s] Unknown param type: %s\n", controllerName, funcName, typ) } if isArray { para.Type = "array" @@ -717,7 +717,7 @@ func getModel(str string) (objectname string, m swagger.Schema, realTypes []stri } } if m.Title == "" { - logger.Warnf("Cannot find the object: %s", str) + beeLogger.Log.Warnf("Cannot find the object: %s", str) // TODO remove when all type have been supported //os.Exit(1) } @@ -732,7 +732,7 @@ func getModel(str string) (objectname string, m swagger.Schema, realTypes []stri func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs map[string]*ast.Package, packageName string) { ts, ok := d.Decl.(*ast.TypeSpec) if !ok { - logger.Fatalf("Unknown type without TypeSec: %v\n", d) + beeLogger.Log.Fatalf("Unknown type without TypeSec: %v\n", d) } // TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc... st, ok := ts.Type.(*ast.StructType) @@ -808,7 +808,7 @@ func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string mp.Default = str2RealType(res[1], realType) } else { - logger.Warnf("Invalid default value: %s", defaultValue) + beeLogger.Log.Warnf("Invalid default value: %s", defaultValue) } } @@ -899,16 +899,6 @@ func isBasicType(Type string) bool { return false } -// regexp get json tag -func grepJSONTag(tag string) string { - r, _ := regexp.Compile(`json:"([^"]*)"`) - matches := r.FindAllStringSubmatch(tag, -1) - if len(matches) > 0 { - return matches[0][1] - } - return "" -} - // append models func appendModels(pkgpath, controllerName string, realTypes []string) { for _, realType := range realTypes { @@ -956,7 +946,7 @@ func str2RealType(s string, typ string) interface{} { } if err != nil { - logger.Warnf("Invalid default value type '%s': %s", typ, s) + beeLogger.Log.Warnf("Invalid default value type '%s': %s", typ, s) return s } diff --git a/hproseapp.go b/hproseapp.go deleted file mode 100644 index 50ba2bd..0000000 --- a/hproseapp.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main - -import ( - "fmt" - "os" - path "path/filepath" - "strings" -) - -var cmdHproseapp = &Command{ - // CustomFlags: true, - UsageLine: "hprose [appname]", - Short: "Creates an RPC application based on Hprose and Beego frameworks", - Long: ` - The command 'hprose' creates an RPC application based on both Beego and Hprose (http://hprose.com/). - - {{"To scaffold out your application, use:"|bold}} - - $ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test] - - If 'conn' is empty, the command will generate a sample application. Otherwise the command - will connect to your database and generate models based on the existing tables. - - The command 'hprose' creates a folder named [appname] with the following structure: - - ├── main.go - ├── {{"conf"|foldername}} - │ └── app.conf - └── {{"models"|foldername}} - └── object.go - └── user.go -`, - PreRun: func(cmd *Command, args []string) { ShowShortVersionBanner() }, - Run: createhprose, -} - -var hproseconf = `appname = {{.Appname}} -httpport = 8080 -runmode = dev -autorender = false -copyrequestbody = true -EnableDocs = true -` -var hproseMaingo = `package main - -import ( - "fmt" - "reflect" - - "{{.Appname}}/models" - "github.com/hprose/hprose-golang/rpc" - - "github.com/astaxie/beego" -) - -func logInvokeHandler( - name string, - args []reflect.Value, - context rpc.Context, - next rpc.NextInvokeHandler) (results []reflect.Value, err error) { - fmt.Printf("%s(%v) = ", name, args) - results, err = next(name, args, context) - fmt.Printf("%v %v\r\n", results, err) - return -} - -func main() { - // Create WebSocketServer - // service := rpc.NewWebSocketService() - - // Create Http Server - service := rpc.NewHTTPService() - - // Use Logger Middleware - service.AddInvokeHandler(logInvokeHandler) - - // Publish Functions - service.AddFunction("AddOne", models.AddOne) - service.AddFunction("GetOne", models.GetOne) - - // Start Service - beego.Handler("/", service) - beego.Run() -} -` - -var hproseMainconngo = `package main - -import ( - "fmt" - "reflect" - - "{{.Appname}}/models" - "github.com/hprose/hprose-golang/rpc" - - "github.com/astaxie/beego" - "github.com/astaxie/beego/orm" - {{.DriverPkg}} -) - -func init() { - orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}") -} - -func logInvokeHandler( - name string, - args []reflect.Value, - context rpc.Context, - next rpc.NextInvokeHandler) (results []reflect.Value, err error) { - fmt.Printf("%s(%v) = ", name, args) - results, err = next(name, args, context) - fmt.Printf("%v %v\r\n", results, err) - return -} - -func main() { - // Create WebSocketServer - // service := rpc.NewWebSocketService() - - // Create Http Server - service := rpc.NewHTTPService() - - // Use Logger Middleware - service.AddInvokeHandler(logInvokeHandler) - - {{HproseFunctionList}} - - // Start Service - beego.Handler("/", service) - beego.Run() -} - -` - -var hproseModels = `package models - -import ( - "errors" - "strconv" - "time" -) - -var ( - Objects map[string]*Object -) - -type Object struct { - ObjectId string - Score int64 - PlayerName string -} - -func init() { - Objects = make(map[string]*Object) - Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} - Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} -} - -func AddOne(object Object) (ObjectId string) { - object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) - Objects[object.ObjectId] = &object - return object.ObjectId -} - -func GetOne(ObjectId string) (object *Object, err error) { - if v, ok := Objects[ObjectId]; ok { - return v, nil - } - return nil, errors.New("ObjectId Not Exist") -} - -func GetAll() map[string]*Object { - return Objects -} - -func Update(ObjectId string, Score int64) (err error) { - if v, ok := Objects[ObjectId]; ok { - v.Score = Score - return nil - } - return errors.New("ObjectId Not Exist") -} - -func Delete(ObjectId string) { - delete(Objects, ObjectId) -} - -` - -var hproseModels2 = `package models - -import ( - "errors" - "strconv" - "time" -) - -var ( - UserList map[string]*User -) - -func init() { - UserList = make(map[string]*User) - u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}} - UserList["user_11111"] = &u -} - -type User struct { - Id string - Username string - Password string - Profile Profile -} - -type Profile struct { - Gender string - Age int - Address string - Email string -} - -func AddUser(u User) string { - u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10) - UserList[u.Id] = &u - return u.Id -} - -func GetUser(uid string) (u *User, err error) { - if u, ok := UserList[uid]; ok { - return u, nil - } - return nil, errors.New("User not exists") -} - -func GetAllUsers() map[string]*User { - return UserList -} - -func UpdateUser(uid string, uu *User) (a *User, err error) { - if u, ok := UserList[uid]; ok { - if uu.Username != "" { - u.Username = uu.Username - } - if uu.Password != "" { - u.Password = uu.Password - } - if uu.Profile.Age != 0 { - u.Profile.Age = uu.Profile.Age - } - if uu.Profile.Address != "" { - u.Profile.Address = uu.Profile.Address - } - if uu.Profile.Gender != "" { - u.Profile.Gender = uu.Profile.Gender - } - if uu.Profile.Email != "" { - u.Profile.Email = uu.Profile.Email - } - return u, nil - } - return nil, errors.New("User Not Exist") -} - -func Login(username, password string) bool { - for _, u := range UserList { - if u.Username == username && u.Password == password { - return true - } - } - return false -} - -func DeleteUser(uid string) { - delete(UserList, uid) -} -` - -var hproseAddFunctions = []string{} - -func init() { - cmdHproseapp.Flag.Var(&tables, "tables", "List of table names separated by a comma.") - cmdHproseapp.Flag.Var(&driver, "driver", "Database driver. Either mysql, postgres or sqlite.") - cmdHproseapp.Flag.Var(&conn, "conn", "Connection string used by the driver to connect to a database instance.") -} - -func createhprose(cmd *Command, args []string) int { - output := cmd.Out() - - if len(args) != 1 { - logger.Fatal("Argument [appname] is missing") - } - - curpath, _ := os.Getwd() - if len(args) > 1 { - cmd.Flag.Parse(args[1:]) - } - apppath, packpath, err := checkEnv(args[0]) - if err != nil { - logger.Fatalf("%s", err) - } - if driver == "" { - driver = "mysql" - } - if conn == "" { - } - - logger.Info("Creating Hprose application...") - - os.MkdirAll(apppath, 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m") - os.Mkdir(path.Join(apppath, "conf"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m") - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m") - WriteToFile(path.Join(apppath, "conf", "app.conf"), - strings.Replace(hproseconf, "{{.Appname}}", args[0], -1)) - - if conn != "" { - logger.Infof("Using '%s' as 'driver'", driver) - logger.Infof("Using '%s' as 'conn'", conn) - logger.Infof("Using '%s' as 'tables'", tables) - generateHproseAppcode(string(driver), string(conn), "1", string(tables), path.Join(curpath, args[0])) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") - maingoContent := strings.Replace(hproseMainconngo, "{{.Appname}}", packpath, -1) - maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1) - maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(hproseAddFunctions, ""), -1) - if driver == "mysql" { - maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1) - } else if driver == "postgres" { - maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1) - } - WriteToFile(path.Join(apppath, "main.go"), - strings.Replace( - maingoContent, - "{{.conn}}", - conn.String(), - -1, - ), - ) - } else { - os.Mkdir(path.Join(apppath, "models"), 0755) - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m") - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "models", "object.go"), apiModels) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2) - - fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "main.go"), - strings.Replace(hproseMaingo, "{{.Appname}}", packpath, -1)) - } - logger.Success("New Hprose application successfully created!") - return 0 -} diff --git a/color.go b/logger/colors/color.go similarity index 77% rename from color.go rename to logger/colors/color.go index 4057961..576280e 100644 --- a/color.go +++ b/logger/colors/color.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package colors import ( "fmt" @@ -53,7 +53,7 @@ func NewModeColorWriter(w io.Writer, mode outputMode) io.Writer { return w } -func bold(message string) string { +func Bold(message string) string { return fmt.Sprintf("\x1b[1m%s\x1b[21m", message) } @@ -102,47 +102,47 @@ func Magenta(message string) string { return fmt.Sprintf("\x1b[35m%s\x1b[0m", message) } -// BlackBold returns a black bold string +// BlackBold returns a black Bold string func BlackBold(message string) string { - return fmt.Sprintf("\x1b[30m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[30m%s\x1b[0m", Bold(message)) } -// WhiteBold returns a white bold string +// WhiteBold returns a white Bold string func WhiteBold(message string) string { - return fmt.Sprintf("\x1b[37m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[37m%s\x1b[0m", Bold(message)) } -// CyanBold returns a cyan bold string +// CyanBold returns a cyan Bold string func CyanBold(message string) string { - return fmt.Sprintf("\x1b[36m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[36m%s\x1b[0m", Bold(message)) } -// BlueBold returns a blue bold string +// BlueBold returns a blue Bold string func BlueBold(message string) string { - return fmt.Sprintf("\x1b[34m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[34m%s\x1b[0m", Bold(message)) } -// RedBold returns a red bold string +// RedBold returns a red Bold string func RedBold(message string) string { - return fmt.Sprintf("\x1b[31m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[31m%s\x1b[0m", Bold(message)) } -// GreenBold returns a green bold string +// GreenBold returns a green Bold string func GreenBold(message string) string { - return fmt.Sprintf("\x1b[32m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[32m%s\x1b[0m", Bold(message)) } -// YellowBold returns a yellow bold string +// YellowBold returns a yellow Bold string func YellowBold(message string) string { - return fmt.Sprintf("\x1b[33m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[33m%s\x1b[0m", Bold(message)) } -// GrayBold returns a gray bold string +// GrayBold returns a gray Bold string func GrayBold(message string) string { - return fmt.Sprintf("\x1b[37m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[37m%s\x1b[0m", Bold(message)) } -// MagentaBold returns a magenta bold string +// MagentaBold returns a magenta Bold string func MagentaBold(message string) string { - return fmt.Sprintf("\x1b[35m%s\x1b[0m", bold(message)) + return fmt.Sprintf("\x1b[35m%s\x1b[0m", Bold(message)) } diff --git a/colorwriter.go b/logger/colors/colorwriter.go similarity index 98% rename from colorwriter.go rename to logger/colors/colorwriter.go index 86201e8..07e69a1 100644 --- a/colorwriter.go +++ b/logger/colors/colorwriter.go @@ -14,7 +14,7 @@ // +build !windows -package main +package colors import "io" diff --git a/colorwriter_windows.go b/logger/colors/colorwriter_windows.go similarity index 99% rename from colorwriter_windows.go rename to logger/colors/colorwriter_windows.go index 7c9e709..d4c567a 100644 --- a/colorwriter_windows.go +++ b/logger/colors/colorwriter_windows.go @@ -14,7 +14,7 @@ // +build windows -package main +package colors import ( "bytes" diff --git a/logger.go b/logger/logger.go similarity index 85% rename from logger.go rename to logger/logger.go index e9e081f..beb5bc5 100644 --- a/logger.go +++ b/logger/logger.go @@ -11,7 +11,7 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. -package main +package beeLogger import ( "errors" @@ -22,19 +22,22 @@ import ( "sync" "sync/atomic" "text/template" + "time" + + "github.com/beego/bee/logger/colors" ) var errInvalidLogLevel = errors.New("logger: invalid log level") const ( - levelCritical = iota - levelFatal - levelSuccess - levelHint - levelDebug - levelInfo - levelWarn + levelDebug = iota levelError + levelFatal + levelCritical + levelSuccess + levelWarn + levelInfo + levelHint ) var ( @@ -42,6 +45,9 @@ var ( instance *BeeLogger once sync.Once ) +var debugMode = os.Getenv("DEBUG_ENABLED") == "1" + +var logLevel = levelInfo // BeeLogger logs logging records to the specified io.Writer type BeeLogger struct { @@ -59,6 +65,8 @@ type LogRecord struct { LineNo int } +var Log = GetBeeLogger(os.Stdout) + var ( logRecordTemplate *template.Template debugLogRecordTemplate *template.Template @@ -80,11 +88,15 @@ func GetBeeLogger(w io.Writer) *BeeLogger { "EndLine": EndLine, } logRecordTemplate, err = template.New("simpleLogFormat").Funcs(funcs).Parse(simpleLogFormat) - MustCheck(err) + if err != nil { + panic(err) + } debugLogRecordTemplate, err = template.New("debugLogFormat").Funcs(funcs).Parse(debugLogFormat) - MustCheck(err) + if err != nil { + panic(err) + } - instance = &BeeLogger{output: NewColorWriter(w)} + instance = &BeeLogger{output: colors.NewColorWriter(w)} }) return instance } @@ -93,7 +105,17 @@ func GetBeeLogger(w io.Writer) *BeeLogger { func (l *BeeLogger) SetOutput(w io.Writer) { l.mu.Lock() defer l.mu.Unlock() - l.output = NewColorWriter(w) + l.output = colors.NewColorWriter(w) +} + +// Now returns the current local time in the specified layout +func Now(layout string) string { + return time.Now().Format(layout) +} + +// EndLine returns the a newline escape character +func EndLine() string { + return "\n" } func (l *BeeLogger) getLevelTag(level int) string { @@ -122,21 +144,21 @@ func (l *BeeLogger) getLevelTag(level int) string { func (l *BeeLogger) getColorLevel(level int) string { switch level { case levelCritical: - return RedBold(l.getLevelTag(level)) + return colors.RedBold(l.getLevelTag(level)) case levelFatal: - return RedBold(l.getLevelTag(level)) + return colors.RedBold(l.getLevelTag(level)) case levelInfo: - return BlueBold(l.getLevelTag(level)) + return colors.BlueBold(l.getLevelTag(level)) case levelHint: - return CyanBold(l.getLevelTag(level)) + return colors.CyanBold(l.getLevelTag(level)) case levelDebug: - return YellowBold(l.getLevelTag(level)) + return colors.YellowBold(l.getLevelTag(level)) case levelError: - return RedBold(l.getLevelTag(level)) + return colors.RedBold(l.getLevelTag(level)) case levelWarn: - return YellowBold(l.getLevelTag(level)) + return colors.YellowBold(l.getLevelTag(level)) case levelSuccess: - return GreenBold(l.getLevelTag(level)) + return colors.GreenBold(l.getLevelTag(level)) default: panic(errInvalidLogLevel) } @@ -145,6 +167,9 @@ func (l *BeeLogger) getColorLevel(level int) string { // mustLog logs the message according to the specified level and arguments. // It panics in case of an error. func (l *BeeLogger) mustLog(level int, message string, args ...interface{}) { + if level > logLevel { + return + } // Acquire the lock l.mu.Lock() defer l.mu.Unlock() @@ -157,13 +182,15 @@ func (l *BeeLogger) mustLog(level int, message string, args ...interface{}) { } err := logRecordTemplate.Execute(l.output, record) - MustCheck(err) + if err != nil { + panic(err) + } } // mustLogDebug logs a debug message only if debug mode // is enabled. i.e. DEBUG_ENABLED="1" func (l *BeeLogger) mustLogDebug(message string, file string, line int, args ...interface{}) { - if !IsDebugEnabled() { + if !debugMode { return } @@ -179,7 +206,9 @@ func (l *BeeLogger) mustLogDebug(message string, file string, line int, args ... Filename: filepath.Base(file), } err := debugLogRecordTemplate.Execute(l.output, record) - MustCheck(err) + if err != nil { + panic(err) + } } // Debug outputs a debug log message diff --git a/main.go b/main.go new file mode 100644 index 0000000..d9401dc --- /dev/null +++ b/main.go @@ -0,0 +1,77 @@ +// Copyright 2013 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +package main + +import ( + "flag" + "log" + "os" + "strings" + + "github.com/beego/bee/cmd" + "github.com/beego/bee/cmd/commands" + "github.com/beego/bee/config" + "github.com/beego/bee/generate/swaggergen" + "github.com/beego/bee/utils" +) + +func main() { + currentpath, _ := os.Getwd() + + flag.Usage = cmd.Usage + flag.Parse() + log.SetFlags(0) + + args := flag.Args() + + if len(args) < 1 { + cmd.Usage() + os.Exit(2) + return + } + + if args[0] == "help" { + cmd.Help(args[1:]) + return + } + + for _, c := range commands.AvailableCommands { + if c.Name() == args[0] && c.Run != nil { + c.Flag.Usage = func() { c.Usage() } + if c.CustomFlags { + args = args[1:] + } else { + c.Flag.Parse(args[1:]) + args = c.Flag.Args() + } + + if c.PreRun != nil { + c.PreRun(c, args) + } + + config.LoadConfig() + + // Check if current directory is inside the GOPATH, + // if so parse the packages inside it. + if strings.Contains(currentpath, utils.GetGOPATHs()[0]+"/src") && cmd.IfGenerateDocs(c.Name(), args) { + swaggergen.ParsePackagesFromDir(currentpath) + } + + os.Exit(c.Run(c, args)) + return + } + } + + utils.PrintErrorAndExit("Unknown subcommand", cmd.ErrorTemplate) +} diff --git a/rundocs.go b/rundocs.go deleted file mode 100644 index 645d391..0000000 --- a/rundocs.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -package main - -import ( - "archive/zip" - "fmt" - "io" - "net/http" - "os" - "strings" -) - -var cmdRundocs = &Command{ - UsageLine: "rundocs [-isDownload=true] [-docport=8888]", - Short: "rundocs will run the docs server,default is 8089", - Long: ` --d meaning will download the docs file from github --p meaning server the Server on which port, default is 8089 - -`, -} - -var ( - swaggerVersion = "2" - swaggerlink = "https://github.com/beego/swagger/archive/v" + swaggerVersion + ".zip" -) - -type docValue string - -func (d *docValue) String() string { - return fmt.Sprint(*d) -} - -func (d *docValue) Set(value string) error { - *d = docValue(value) - return nil -} - -var isDownload docValue -var docport docValue - -func init() { - cmdRundocs.Run = runDocs - cmdRundocs.PreRun = func(cmd *Command, args []string) { ShowShortVersionBanner() } - cmdRundocs.Flag.Var(&isDownload, "isDownload", "weather download the Swagger Docs") - cmdRundocs.Flag.Var(&docport, "docport", "doc server port") -} - -func runDocs(cmd *Command, args []string) int { - if isDownload == "true" { - downloadFromURL(swaggerlink, "swagger.zip") - err := unzipAndDelete("swagger.zip") - if err != nil { - logger.Errorf("Error while unzipping 'swagger.zip' file: %s", err) - } - } - if docport == "" { - docport = "8089" - } - if _, err := os.Stat("swagger"); err != nil && os.IsNotExist(err) { - logger.Fatal("No Swagger dist found. Run: bee rundocs -isDownload=true") - } - - logger.Infof("Starting the docs server on: http://127.0.0.1:%s", docport) - - err := http.ListenAndServe(":"+string(docport), http.FileServer(http.Dir("swagger"))) - if err != nil { - logger.Fatalf("%s", err) - } - return 0 -} - -func downloadFromURL(url, fileName string) { - var down bool - if fd, err := os.Stat(fileName); err != nil && os.IsNotExist(err) { - down = true - } else if fd.Size() == int64(0) { - down = true - } else { - logger.Infof("'%s' already exists", fileName) - return - } - if down { - logger.Infof("Downloading '%s' to '%s'...", url, fileName) - output, err := os.Create(fileName) - if err != nil { - logger.Errorf("Error while creating '%s': %s", fileName, err) - return - } - defer output.Close() - - response, err := http.Get(url) - if err != nil { - logger.Errorf("Error while downloading '%s': %s", url, err) - return - } - defer response.Body.Close() - - n, err := io.Copy(output, response.Body) - if err != nil { - logger.Errorf("Error while downloading '%s': %s", url, err) - return - } - logger.Successf("%d bytes downloaded!", n) - } -} - -func unzipAndDelete(src string) error { - logger.Infof("Unzipping '%s'...", src) - r, err := zip.OpenReader(src) - if err != nil { - return err - } - defer r.Close() - - rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger") - for _, f := range r.File { - rc, err := f.Open() - if err != nil { - return err - } - defer rc.Close() - - fname := rp.Replace(f.Name) - if f.FileInfo().IsDir() { - os.MkdirAll(fname, f.Mode()) - } else { - f, err := os.OpenFile( - fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) - if err != nil { - return err - } - defer f.Close() - - _, err = io.Copy(f, rc) - if err != nil { - return err - } - } - } - logger.Successf("Done! Deleting '%s'...", src) - return os.RemoveAll(src) -} diff --git a/test.go b/test.go deleted file mode 100644 index f8be62b..0000000 --- a/test.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2013 bee authors -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package main - -import ( - "os" - "os/exec" - path "path/filepath" - "time" - - _ "github.com/smartystreets/goconvey/convey" -) - -var cmdTest = &Command{ - UsageLine: "test [appname]", - Short: "test the app", - Long: ``, -} - -func init() { - cmdTest.Run = testApp - cmdTest.PreRun = func(cmd *Command, args []string) { ShowShortVersionBanner() } -} - -func safePathAppend(arr []string, paths ...string) []string { - for _, path := range paths { - if pathExists(path) { - arr = append(arr, path) - } - } - return arr -} - -func pathExists(path string) bool { - _, err := os.Stat(path) - return err == nil || os.IsExist(err) -} - -var started = make(chan bool) - -func testApp(cmd *Command, args []string) int { - if len(args) != 1 { - logger.Fatalf("Failed to start: %s", "argument 'appname' is missing") - } - - currpath, _ := os.Getwd() - - logger.Debugf("Current path: %s", __FILE__(), __LINE__(), currpath) - - err := loadConfig() - if err != nil { - logger.Fatalf("Failed to load configuration: %s", err) - } - var paths []string - readAppDirectories(currpath, &paths) - - NewWatcher(paths, nil, false) - appname = args[0] - for { - select { - case <-started: - runTest() - } - } -} - -func runTest() { - logger.Info("Start testing...") - time.Sleep(time.Second * 1) - crupwd, _ := os.Getwd() - testDir := path.Join(crupwd, "tests") - if pathExists(testDir) { - os.Chdir(testDir) - } - - var err error - icmd := exec.Command("go", "test") - icmd.Stdout = os.Stdout - icmd.Stderr = os.Stderr - logger.Info("============== Test Begin ===================") - err = icmd.Run() - logger.Info("============== Test End =====================") - - if err != nil { - logger.Error("============== Test failed ===================") - logger.Errorf("Cause: %s", err) - return - } - logger.Success("Test Completed") -} diff --git a/testdata/router/router.go b/testdata/router/router.go deleted file mode 100644 index 8a54102..0000000 --- a/testdata/router/router.go +++ /dev/null @@ -1,28 +0,0 @@ -package router - -import ( - "github.com/astaxie/beego" -) - -type Router struct { - beego.Controller -} - -func (r *Router) Get() { - -} - -func (r *Router) Post() { - -} - -type Controller struct { -} - -func (c *Controller) Put() { - -} - -func (c *Controller) Delete() { - -} diff --git a/utils/doc_value.go b/utils/doc_value.go new file mode 100644 index 0000000..daf407d --- /dev/null +++ b/utils/doc_value.go @@ -0,0 +1,14 @@ +package utils + +import "fmt" + +type DocValue string + +func (d *DocValue) String() string { + return fmt.Sprint(*d) +} + +func (d *DocValue) Set(value string) error { + *d = DocValue(value) + return nil +} diff --git a/utils/list_opts.go b/utils/list_opts.go new file mode 100644 index 0000000..28c2a10 --- /dev/null +++ b/utils/list_opts.go @@ -0,0 +1,14 @@ +package utils + +import "fmt" + +type ListOpts []string + +func (opts *ListOpts) String() string { + return fmt.Sprint(*opts) +} + +func (opts *ListOpts) Set(value string) error { + *opts = append(*opts, value) + return nil +} diff --git a/utils/notification.go b/utils/notification.go new file mode 100644 index 0000000..b19b49f --- /dev/null +++ b/utils/notification.go @@ -0,0 +1,84 @@ +// Copyright 2017 bee authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +package utils + +import ( + "fmt" + "os/exec" + "strconv" + "strings" + + "runtime" + + "github.com/beego/bee/config" +) + +const appName = "Beego" + +func Notify(text, title string) { + if !config.Conf.EnableNotification { + return + } + switch runtime.GOOS { + case "darwin": + osxNotify(text, title) + case "linux": + linuxNotify(text, title) + case "windows": + windowsNotify(text, title) + } +} + +func osxNotify(text, title string) { + var cmd *exec.Cmd + if existTerminalNotifier() { + cmd = exec.Command("terminal-notifier", "-title", appName, "-message", text, "-subtitle", title) + } else if MacOSVersionSupport() { + notification := fmt.Sprintf("display notification \"%s\" with title \"%s\" subtitle \"%s\"", text, appName, title) + cmd = exec.Command("osascript", "-e", notification) + } else { + cmd = exec.Command("growlnotify", "-n", appName, "-m", title) + } + cmd.Run() +} + +func windowsNotify(text, title string) { + exec.Command("growlnotify", "/i:", "", "/t:", title, text).Run() +} + +func linuxNotify(text, title string) { + exec.Command("notify-send", "-i", "", title, text).Run() +} + +func existTerminalNotifier() bool { + cmd := exec.Command("which", "terminal-notifier") + err := cmd.Start() + if err != nil { + return false + } + err = cmd.Wait() + return err != nil +} + +func MacOSVersionSupport() bool { + cmd := exec.Command("sw_vers", "-productVersion") + check, _ := cmd.Output() + version := strings.Split(string(check), ".") + major, _ := strconv.Atoi(version[0]) + minor, _ := strconv.Atoi(version[1]) + if major < 10 || (major == 10 && minor < 9) { + return false + } + return true +} diff --git a/utils/str_flag.go b/utils/str_flag.go new file mode 100644 index 0000000..e65fc4e --- /dev/null +++ b/utils/str_flag.go @@ -0,0 +1,15 @@ +package utils + +import "fmt" + +// The string flag list, implemented flag.Value interface +type StrFlags []string + +func (s *StrFlags) String() string { + return fmt.Sprintf("%s", *s) +} + +func (s *StrFlags) Set(value string) error { + *s = append(*s, value) + return nil +} diff --git a/util.go b/utils/utils.go similarity index 64% rename from util.go rename to utils/utils.go index 4a97e6c..b41de0a 100644 --- a/util.go +++ b/utils/utils.go @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. -package main +package utils import ( "bytes" @@ -26,7 +26,10 @@ import ( "runtime" "strings" "text/template" - "time" + "unicode" + + beeLogger "github.com/beego/bee/logger" + "github.com/beego/bee/logger/colors" ) // Go is a basic promise implementation: it wraps calls a function in a goroutine @@ -39,18 +42,8 @@ func Go(f func() error) chan error { return ch } -// Now returns the current local time in the specified layout -func Now(layout string) string { - return time.Now().Format(layout) -} - -// EndLine returns the a newline escape character -func EndLine() string { - return "\n" -} - // IsExist returns whether a file or directory exists. -func isExist(path string) bool { +func IsExist(path string) bool { _, err := os.Stat(path) return err == nil || os.IsExist(err) } @@ -107,7 +100,7 @@ func IsBeegoProject(thePath string) bool { }() if err := <-c; err != nil { - logger.Fatalf("Unable to walk '%s' tree: %s", thePath, err) + beeLogger.Log.Fatalf("Unable to walk '%s' tree: %s", thePath, err) } if len(mainFiles) > 0 { @@ -121,7 +114,7 @@ func IsBeegoProject(thePath string) bool { func SearchGOPATHs(app string) (bool, string, string) { gps := GetGOPATHs() if len(gps) == 0 { - logger.Fatal("GOPATH environment variable is not set or empty") + beeLogger.Log.Fatal("GOPATH environment variable is not set or empty") } // Lookup the application inside the user workspace(s) @@ -135,7 +128,7 @@ func SearchGOPATHs(app string) (bool, string, string) { currentPath = app } - if isExist(currentPath) { + if IsExist(currentPath) { return true, gopath, currentPath } } @@ -147,11 +140,11 @@ func SearchGOPATHs(app string) (bool, string, string) { // confirmations. If the input is not recognized, it will ask again. The function does not return // until it gets a valid response from the user. Typically, you should use fmt to print out a question // before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)") -func askForConfirmation() bool { +func AskForConfirmation() bool { var response string _, err := fmt.Scanln(&response) if err != nil { - logger.Fatalf("%s", err) + beeLogger.Log.Fatalf("%s", err) } okayResponses := []string{"y", "Y", "yes", "Yes", "YES"} nokayResponses := []string{"n", "N", "no", "No", "NO"} @@ -161,7 +154,7 @@ func askForConfirmation() bool { return false } else { fmt.Println("Please type yes or no and then press enter:") - return askForConfirmation() + return AskForConfirmation() } } @@ -175,7 +168,7 @@ func containsString(slice []string, element string) bool { } // snake string, XxYy to xx_yy -func snakeString(s string) string { +func SnakeString(s string) string { data := make([]byte, 0, len(s)*2) j := false num := len(s) @@ -192,17 +185,17 @@ func snakeString(s string) string { return strings.ToLower(string(data[:])) } -func camelString(s string) string { +func CamelString(s string) string { data := make([]byte, 0, len(s)) j := false k := false num := len(s) - 1 for i := 0; i <= num; i++ { d := s[i] - if k == false && d >= 'A' && d <= 'Z' { + if !k && d >= 'A' && d <= 'Z' { k = true } - if d >= 'a' && d <= 'z' && (j || k == false) { + if d >= 'a' && d <= 'z' && (j || !k) { d = d - 32 j = false k = true @@ -218,7 +211,7 @@ func camelString(s string) string { // camelCase converts a _ delimited string to camel case // e.g. very_important_person => VeryImportantPerson -func camelCase(in string) string { +func CamelCase(in string) string { tokens := strings.Split(in, "_") for i := range tokens { tokens[i] = strings.Title(strings.Trim(tokens[i], " ")) @@ -227,25 +220,13 @@ func camelCase(in string) string { } // formatSourceCode formats source files -func formatSourceCode(filename string) { +func FormatSourceCode(filename string) { cmd := exec.Command("gofmt", "-w", filename) if err := cmd.Run(); err != nil { - logger.Warnf("Error while running gofmt: %s", err) + beeLogger.Log.Warnf("Error while running gofmt: %s", err) } } -// The string flag list, implemented flag.Value interface -type strFlags []string - -func (s *strFlags) String() string { - return fmt.Sprintf("%s", *s) -} - -func (s *strFlags) Set(value string) error { - *s = append(*s, value) - return nil -} - // CloseFile attempts to close the passed file // or panics with the actual error func CloseFile(f *os.File) { @@ -260,11 +241,6 @@ func MustCheck(err error) { } } -func exitPrint(con string) { - fmt.Fprintln(os.Stderr, con) - os.Exit(2) -} - // WriteToFile creates a file and writes content to it func WriteToFile(filename, content string) { f, err := os.Create(filename) @@ -274,20 +250,14 @@ func WriteToFile(filename, content string) { MustCheck(err) } -// IsDebugEnabled checks if DEBUG_ENABLED is set or not -func IsDebugEnabled() bool { - debugMode := os.Getenv("DEBUG_ENABLED") - return map[string]bool{"1": true, "0": false}[debugMode] -} - // __FILE__ returns the file name in which the function was invoked -func __FILE__() string { +func FILE() string { _, file, _, _ := runtime.Caller(1) return file } // __LINE__ returns the line number at which the function was invoked -func __LINE__() int { +func LINE() int { _, _, line, _ := runtime.Caller(1) return line } @@ -296,9 +266,9 @@ func __LINE__() int { func BeeFuncMap() template.FuncMap { return template.FuncMap{ "trim": strings.TrimSpace, - "bold": bold, - "headline": MagentaBold, - "foldername": RedBold, + "bold": colors.Bold, + "headline": colors.MagentaBold, + "foldername": colors.RedBold, "endline": EndLine, "tmpltostr": TmplToString, } @@ -315,3 +285,125 @@ func TmplToString(tmpl string, data interface{}) string { return doc.String() } + +// EndLine returns the a newline escape character +func EndLine() string { + return "\n" +} + +func Tmpl(text string, data interface{}) { + output := colors.NewColorWriter(os.Stderr) + + t := template.New("Usage").Funcs(BeeFuncMap()) + template.Must(t.Parse(text)) + + err := t.Execute(output, data) + if err != nil { + beeLogger.Log.Error(err.Error()) + } +} + +func CheckEnv(appname string) (apppath, packpath string, err error) { + gps := GetGOPATHs() + if len(gps) == 0 { + beeLogger.Log.Fatal("GOPATH environment variable is not set or empty") + } + currpath, _ := os.Getwd() + currpath = path.Join(currpath, appname) + for _, gpath := range gps { + gsrcpath := path.Join(gpath, "src") + if strings.HasPrefix(currpath, gsrcpath) { + packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(filepath.Separator), "/", -1) + return currpath, packpath, nil + } + } + + // In case of multiple paths in the GOPATH, by default + // we use the first path + gopath := gps[0] + + beeLogger.Log.Warn("You current workdir is not inside $GOPATH/src.") + beeLogger.Log.Debugf("GOPATH: %s", FILE(), LINE(), gopath) + + gosrcpath := path.Join(gopath, "src") + apppath = path.Join(gosrcpath, appname) + + if _, e := os.Stat(apppath); !os.IsNotExist(e) { + err = fmt.Errorf("Cannot create application without removing '%s' first", apppath) + beeLogger.Log.Errorf("Path '%s' already exists", apppath) + return + } + packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(filepath.Separator)), "/") + return +} + +func PrintErrorAndExit(message, errorTemplate string) { + Tmpl(fmt.Sprintf(errorTemplate, message), nil) + os.Exit(2) +} + +// GoCommand executes the passed command using Go tool +func GoCommand(command string, args ...string) error { + allargs := []string{command} + allargs = append(allargs, args...) + goBuild := exec.Command("go", allargs...) + goBuild.Stderr = os.Stderr + return goBuild.Run() +} + +// SplitQuotedFields is like strings.Fields but ignores spaces +// inside areas surrounded by single quotes. +// To specify a single quote use backslash to escape it: '\'' +func SplitQuotedFields(in string) []string { + type stateEnum int + const ( + inSpace stateEnum = iota + inField + inQuote + inQuoteEscaped + ) + state := inSpace + r := []string{} + var buf bytes.Buffer + + for _, ch := range in { + switch state { + case inSpace: + if ch == '\'' { + state = inQuote + } else if !unicode.IsSpace(ch) { + buf.WriteRune(ch) + state = inField + } + + case inField: + if ch == '\'' { + state = inQuote + } else if unicode.IsSpace(ch) { + r = append(r, buf.String()) + buf.Reset() + } else { + buf.WriteRune(ch) + } + + case inQuote: + if ch == '\'' { + state = inField + } else if ch == '\\' { + state = inQuoteEscaped + } else { + buf.WriteRune(ch) + } + + case inQuoteEscaped: + buf.WriteRune(ch) + state = inQuote + } + } + + if buf.Len() != 0 { + r = append(r, buf.String()) + } + + return r +} diff --git a/vendor/github.com/astaxie/beego/utils/safemap.go b/vendor/github.com/astaxie/beego/utils/safemap.go index 2e438f2..1793030 100644 --- a/vendor/github.com/astaxie/beego/utils/safemap.go +++ b/vendor/github.com/astaxie/beego/utils/safemap.go @@ -61,10 +61,8 @@ func (m *BeeMap) Set(k interface{}, v interface{}) bool { func (m *BeeMap) Check(k interface{}) bool { m.lock.RLock() defer m.lock.RUnlock() - if _, ok := m.bm[k]; !ok { - return false - } - return true + _, ok := m.bm[k] + return ok } // Delete the given key and value. @@ -84,3 +82,10 @@ func (m *BeeMap) Items() map[interface{}]interface{} { } return r } + +// Count returns the number of items within the map. +func (m *BeeMap) Count() int { + m.lock.RLock() + defer m.lock.RUnlock() + return len(m.bm) +} diff --git a/vendor/github.com/jtolds/gls/LICENSE b/vendor/github.com/derekparker/delve/LICENSE similarity index 94% rename from vendor/github.com/jtolds/gls/LICENSE rename to vendor/github.com/derekparker/delve/LICENSE index 9b4a822..5ee9d2f 100644 --- a/vendor/github.com/jtolds/gls/LICENSE +++ b/vendor/github.com/derekparker/delve/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2013, Space Monkey, Inc. +The MIT License (MIT) + +Copyright (c) 2014 Derek Parker 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 diff --git a/vendor/github.com/derekparker/delve/pkg/config/config.go b/vendor/github.com/derekparker/delve/pkg/config/config.go new file mode 100644 index 0000000..3abb485 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/config/config.go @@ -0,0 +1,134 @@ +package config + +import ( + "fmt" + "io/ioutil" + "os" + "os/user" + "path" + + yaml "gopkg.in/yaml.v2" +) + +const ( + configDir string = ".dlv" + configFile string = "config.yml" +) + +// Describes a rule for substitution of path to source code file. +type SubstitutePathRule struct { + // Directory path will be substituted if it matches `From`. + From string + // Path to which substitution is performed. + To string +} + +// Slice of source code path substitution rules. +type SubstitutePathRules []SubstitutePathRule + +// Config defines all configuration options available to be set through the config file. +type Config struct { + // Commands aliases. + Aliases map[string][]string + // Source code path substitution rules. + SubstitutePath SubstitutePathRules `yaml:"substitute-path"` +} + +// LoadConfig attempts to populate a Config object from the config.yml file. +func LoadConfig() *Config { + err := createConfigPath() + if err != nil { + fmt.Printf("Could not create config directory: %v.", err) + return nil + } + fullConfigFile, err := GetConfigFilePath(configFile) + if err != nil { + fmt.Printf("Unable to get config file path: %v.", err) + return nil + } + + f, err := os.Open(fullConfigFile) + if err != nil { + createDefaultConfig(fullConfigFile) + return nil + } + defer func() { + err := f.Close() + if err != nil { + fmt.Printf("Closing config file failed: %v.", err) + } + }() + + data, err := ioutil.ReadAll(f) + if err != nil { + fmt.Printf("Unable to read config data: %v.", err) + return nil + } + + var c Config + err = yaml.Unmarshal(data, &c) + if err != nil { + fmt.Printf("Unable to decode config file: %v.", err) + return nil + } + + return &c +} + +func createDefaultConfig(path string) { + f, err := os.Create(path) + if err != nil { + fmt.Printf("Unable to create config file: %v.", err) + return + } + defer func() { + err := f.Close() + if err != nil { + fmt.Printf("Closing config file failed: %v.", err) + } + }() + err = writeDefaultConfig(f) + if err != nil { + fmt.Printf("Unable to write default configuration: %v.", err) + } +} + +func writeDefaultConfig(f *os.File) error { + _, err := f.WriteString( + `# Configuration file for the delve debugger. + +# This is the default configuration file. Available options are provided, but disabled. +# Delete the leading hash mark to enable an item. + +# Provided aliases will be added to the default aliases for a given command. +aliases: + # command: ["alias1", "alias2"] + +# Define sources path substitution rules. Can be used to rewrite a source path stored +# in program's debug information, if the sources were moved to a different place +# between compilation and debugging. +# Note that substitution rules will not be used for paths passed to "break" and "trace" +# commands. +substitute-path: + # - {from: path, to: path} +`) + return err +} + +// createConfigPath creates the directory structure at which all config files are saved. +func createConfigPath() error { + path, err := GetConfigFilePath("") + if err != nil { + return err + } + return os.MkdirAll(path, 0700) +} + +// GetConfigFilePath gets the full path to the given config file name. +func GetConfigFilePath(file string) (string, error) { + usr, err := user.Current() + if err != nil { + return "", err + } + return path.Join(usr.HomeDir, configDir, file), nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/frame/entries.go b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/entries.go new file mode 100644 index 0000000..caca2ce --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/entries.go @@ -0,0 +1,95 @@ +package frame + +import ( + "encoding/binary" + "fmt" + "sort" +) + +// Represents a Common Information Entry in +// the Dwarf .debug_frame section. +type CommonInformationEntry struct { + Length uint32 + CIE_id uint32 + Version uint8 + Augmentation string + CodeAlignmentFactor uint64 + DataAlignmentFactor int64 + ReturnAddressRegister uint64 + InitialInstructions []byte +} + +// Represents a Frame Descriptor Entry in the +// Dwarf .debug_frame section. +type FrameDescriptionEntry struct { + Length uint32 + CIE *CommonInformationEntry + Instructions []byte + begin, end uint64 + order binary.ByteOrder +} + +// Returns whether or not the given address is within the +// bounds of this frame. +func (fde *FrameDescriptionEntry) Cover(addr uint64) bool { + if (addr - fde.begin) < fde.end { + return true + } + return false +} + +// Address of first location for this frame. +func (fde *FrameDescriptionEntry) Begin() uint64 { + return fde.begin +} + +// Address of last location for this frame. +func (fde *FrameDescriptionEntry) End() uint64 { + return fde.begin + fde.end +} + +// Set up frame for the given PC. +func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext { + return executeDwarfProgramUntilPC(fde, pc) +} + +// Return the offset from the current SP that the return address is stored at. +func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) (frameOffset, returnAddressOffset int64) { + frame := fde.EstablishFrame(pc) + return frame.cfa.offset, frame.regs[fde.CIE.ReturnAddressRegister].offset +} + +type FrameDescriptionEntries []*FrameDescriptionEntry + +func NewFrameIndex() FrameDescriptionEntries { + return make(FrameDescriptionEntries, 0, 1000) +} + +type NoFDEForPCError struct { + PC uint64 +} + +func (err *NoFDEForPCError) Error() string { + return fmt.Sprintf("could not find FDE for PC %#v", err.PC) +} + +// Returns the Frame Description Entry for the given PC. +func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) { + idx := sort.Search(len(fdes), func(i int) bool { + if fdes[i].Cover(pc) { + return true + } + if fdes[i].LessThan(pc) { + return false + } + return true + }) + if idx == len(fdes) { + return nil, &NoFDEForPCError{pc} + } + return fdes[idx], nil +} + +func (frame *FrameDescriptionEntry) LessThan(pc uint64) bool { + return frame.End() <= pc +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/frame/expression_constants.go b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/expression_constants.go new file mode 100644 index 0000000..95240cf --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/expression_constants.go @@ -0,0 +1,164 @@ +package frame + +// Operation opcodes +const ( + DW_OP_addr = 0x03 + DW_OP_const1s = 0x09 +) + +const ( + DW_OP_const2u = 0x0a + DW_OP_const2s = 0x0b + DW_OP_const4u = iota + DW_OP_const4s + DW_OP_const8u + DW_OP_const8s + DW_OP_constu + DW_OP_consts + DW_OP_dup + DW_OP_drop + DW_OP_over + DW_OP_pick + DW_OP_swap + DW_OP_rot + DW_OP_xderef + DW_OP_abs + DW_OP_and + DW_OP_div + DW_OP_minus + DW_OP_mod + DW_OP_mul + DW_OP_neg + DW_OP_not + DW_OP_or + DW_OP_plus + DW_OP_plus_uconst + DW_OP_shl + DW_OP_shr + DW_OP_shra + DW_OP_xor + DW_OP_skip + DW_OP_bra + DW_OP_eq + DW_OP_ge + DW_OP_gt + DW_OP_le + DW_OP_lt + DW_OP_ne +) + +const ( + DW_OP_lit0 = 0x30 + DW_OP_lit1 = 0x31 + DW_OP_lit2 = iota + DW_OP_lit3 + DW_OP_lit4 + DW_OP_lit5 + DW_OP_lit6 + DW_OP_lit7 + DW_OP_lit8 + DW_OP_lit9 + DW_OP_lit10 + DW_OP_lit11 + DW_OP_lit12 + DW_OP_lit13 + DW_OP_lit14 + DW_OP_lit15 + DW_OP_lit16 + DW_OP_lit17 + DW_OP_lit18 + DW_OP_lit19 + DW_OP_lit20 + DW_OP_lit21 + DW_OP_lit22 + DW_OP_lit23 + DW_OP_lit24 + DW_OP_lit25 + DW_OP_lit26 + DW_OP_lit27 + DW_OP_lit28 + DW_OP_lit29 + DW_OP_lit30 + DW_OP_lit31 + DW_OP_reg0 + DW_OP_reg1 + DW_OP_reg2 + DW_OP_reg3 + DW_OP_reg4 + DW_OP_reg5 + DW_OP_reg6 + DW_OP_reg7 + DW_OP_reg8 + DW_OP_reg9 + DW_OP_reg10 + DW_OP_reg11 + DW_OP_reg12 + DW_OP_reg13 + DW_OP_reg14 + DW_OP_reg15 + DW_OP_reg16 + DW_OP_reg17 + DW_OP_reg18 + DW_OP_reg19 + DW_OP_reg20 + DW_OP_reg21 + DW_OP_reg22 + DW_OP_reg23 + DW_OP_reg24 + DW_OP_reg25 + DW_OP_reg26 + DW_OP_reg27 + DW_OP_reg28 + DW_OP_reg29 + DW_OP_reg30 + DW_OP_reg31 + DW_OP_breg0 + DW_OP_breg1 + DW_OP_breg2 + DW_OP_breg3 + DW_OP_breg4 + DW_OP_breg5 + DW_OP_breg6 + DW_OP_breg7 + DW_OP_breg8 + DW_OP_breg9 + DW_OP_breg10 + DW_OP_breg11 + DW_OP_breg12 + DW_OP_breg13 + DW_OP_breg14 + DW_OP_breg15 + DW_OP_breg16 + DW_OP_breg17 + DW_OP_breg18 + DW_OP_breg19 + DW_OP_breg20 + DW_OP_breg21 + DW_OP_breg22 + DW_OP_breg23 + DW_OP_breg24 + DW_OP_breg25 + DW_OP_breg26 + DW_OP_breg27 + DW_OP_breg28 + DW_OP_breg29 + DW_OP_breg30 + DW_OP_breg31 + DW_OP_regx + DW_OP_fbreg + DW_OP_bregx + DW_OP_piece + DW_OP_deref_size + DW_OP_xderef_size + DW_OP_nop + DW_OP_push_object_address + DW_OP_call2 + DW_OP_call4 + DW_OP_call_ref + DW_OP_form_tls_address + DW_OP_call_frame_cfa + DW_OP_bit_piece + + DW_OP_lo_user = 0xe0 + DW_OP_hi_user = 0xff +) diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/frame/parser.go b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/parser.go new file mode 100644 index 0000000..9afa5a2 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/parser.go @@ -0,0 +1,125 @@ +// Package frame contains data structures and +// related functions for parsing and searching +// through Dwarf .debug_frame data. +package frame + +import ( + "bytes" + "encoding/binary" + + "github.com/derekparker/delve/pkg/dwarf/util" +) + +type parsefunc func(*parseContext) parsefunc + +type parseContext struct { + buf *bytes.Buffer + entries FrameDescriptionEntries + common *CommonInformationEntry + frame *FrameDescriptionEntry + length uint32 +} + +// Parse takes in data (a byte slice) and returns a slice of +// commonInformationEntry structures. Each commonInformationEntry +// has a slice of frameDescriptionEntry structures. +func Parse(data []byte, order binary.ByteOrder) FrameDescriptionEntries { + var ( + buf = bytes.NewBuffer(data) + pctx = &parseContext{buf: buf, entries: NewFrameIndex()} + ) + + for fn := parselength; buf.Len() != 0; { + fn = fn(pctx) + } + + for i := range pctx.entries { + pctx.entries[i].order = order + } + + return pctx.entries +} + +func cieEntry(data []byte) bool { + return bytes.Equal(data, []byte{0xff, 0xff, 0xff, 0xff}) +} + +func parselength(ctx *parseContext) parsefunc { + var data = ctx.buf.Next(8) + + ctx.length = binary.LittleEndian.Uint32(data[:4]) - 4 // take off the length of the CIE id / CIE pointer. + + if cieEntry(data[4:]) { + ctx.common = &CommonInformationEntry{Length: ctx.length} + return parseCIE + } + + ctx.frame = &FrameDescriptionEntry{Length: ctx.length, CIE: ctx.common} + return parseFDE +} + +func parseFDE(ctx *parseContext) parsefunc { + r := ctx.buf.Next(int(ctx.length)) + + ctx.frame.begin = binary.LittleEndian.Uint64(r[:8]) + ctx.frame.end = binary.LittleEndian.Uint64(r[8:16]) + + // Insert into the tree after setting address range begin + // otherwise compares won't work. + ctx.entries = append(ctx.entries, ctx.frame) + + // The rest of this entry consists of the instructions + // so we can just grab all of the data from the buffer + // cursor to length. + ctx.frame.Instructions = r[16:] + ctx.length = 0 + + return parselength +} + +func parseCIE(ctx *parseContext) parsefunc { + data := ctx.buf.Next(int(ctx.length)) + buf := bytes.NewBuffer(data) + // parse version + ctx.common.Version = data[0] + + // parse augmentation + ctx.common.Augmentation, _ = util.ParseString(buf) + + // parse code alignment factor + ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf) + + // parse data alignment factor + ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf) + + // parse return address register + ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf) + + // parse initial instructions + // The rest of this entry consists of the instructions + // so we can just grab all of the data from the buffer + // cursor to length. + ctx.common.InitialInstructions = buf.Bytes() //ctx.buf.Next(int(ctx.length)) + ctx.length = 0 + + return parselength +} + +// DwarfEndian determines the endianness of the DWARF by using the version number field in the debug_info section +// Trick borrowed from "debug/dwarf".New() +func DwarfEndian(infoSec []byte) binary.ByteOrder { + if len(infoSec) < 6 { + return binary.BigEndian + } + x, y := infoSec[4], infoSec[5] + switch { + case x == 0 && y == 0: + return binary.BigEndian + case x == 0: + return binary.BigEndian + case y == 0: + return binary.LittleEndian + default: + return binary.BigEndian + } +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/frame/table.go b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/table.go new file mode 100644 index 0000000..03788f7 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/frame/table.go @@ -0,0 +1,429 @@ +package frame + +import ( + "bytes" + "encoding/binary" + "fmt" + + "github.com/derekparker/delve/pkg/dwarf/util" +) + +type CurrentFrameAddress struct { + register uint64 + offset int64 + expression []byte + rule byte +} + +type DWRule struct { + rule byte + offset int64 + newreg uint64 + expression []byte +} + +type FrameContext struct { + loc uint64 + order binary.ByteOrder + address uint64 + cfa CurrentFrameAddress + regs map[uint64]DWRule + initialRegs map[uint64]DWRule + prevRegs map[uint64]DWRule + buf *bytes.Buffer + cie *CommonInformationEntry + codeAlignment uint64 + dataAlignment int64 +} + +func (fctx *FrameContext) CFAOffset() int64 { + return fctx.cfa.offset +} + +// Instructions used to recreate the table from the .debug_frame data. +const ( + DW_CFA_nop = 0x0 // No ops + DW_CFA_set_loc = 0x01 // op1: address + DW_CFA_advance_loc1 = iota // op1: 1-bytes delta + DW_CFA_advance_loc2 // op1: 2-byte delta + DW_CFA_advance_loc4 // op1: 4-byte delta + DW_CFA_offset_extended // op1: ULEB128 register, op2: ULEB128 offset + DW_CFA_restore_extended // op1: ULEB128 register + DW_CFA_undefined // op1: ULEB128 register + DW_CFA_same_value // op1: ULEB128 register + DW_CFA_register // op1: ULEB128 register, op2: ULEB128 register + DW_CFA_remember_state // No ops + DW_CFA_restore_state // No ops + DW_CFA_def_cfa // op1: ULEB128 register, op2: ULEB128 offset + DW_CFA_def_cfa_register // op1: ULEB128 register + DW_CFA_def_cfa_offset // op1: ULEB128 offset + DW_CFA_def_cfa_expression // op1: BLOCK + DW_CFA_expression // op1: ULEB128 register, op2: BLOCK + DW_CFA_offset_extended_sf // op1: ULEB128 register, op2: SLEB128 BLOCK + DW_CFA_def_cfa_sf // op1: ULEB128 register, op2: SLEB128 offset + DW_CFA_def_cfa_offset_sf // op1: SLEB128 offset + DW_CFA_val_offset // op1: ULEB128, op2: ULEB128 + DW_CFA_val_offset_sf // op1: ULEB128, op2: SLEB128 + DW_CFA_val_expression // op1: ULEB128, op2: BLOCK + DW_CFA_lo_user = 0x1c // op1: BLOCK + DW_CFA_hi_user = 0x3f // op1: ULEB128 register, op2: BLOCK + DW_CFA_advance_loc = (0x1 << 6) // High 2 bits: 0x1, low 6: delta + DW_CFA_offset = (0x2 << 6) // High 2 bits: 0x2, low 6: register + DW_CFA_restore = (0x3 << 6) // High 2 bits: 0x3, low 6: register +) + +// Rules defined for register values. +const ( + rule_undefined = iota + rule_sameval + rule_offset + rule_valoffset + rule_register + rule_expression + rule_valexpression + rule_architectural +) + +const low_6_offset = 0x3f + +type instruction func(frame *FrameContext) + +// // Mapping from DWARF opcode to function. +var fnlookup = map[byte]instruction{ + DW_CFA_advance_loc: advanceloc, + DW_CFA_offset: offset, + DW_CFA_restore: restore, + DW_CFA_set_loc: setloc, + DW_CFA_advance_loc1: advanceloc1, + DW_CFA_advance_loc2: advanceloc2, + DW_CFA_advance_loc4: advanceloc4, + DW_CFA_offset_extended: offsetextended, + DW_CFA_restore_extended: restoreextended, + DW_CFA_undefined: undefined, + DW_CFA_same_value: samevalue, + DW_CFA_register: register, + DW_CFA_remember_state: rememberstate, + DW_CFA_restore_state: restorestate, + DW_CFA_def_cfa: defcfa, + DW_CFA_def_cfa_register: defcfaregister, + DW_CFA_def_cfa_offset: defcfaoffset, + DW_CFA_def_cfa_expression: defcfaexpression, + DW_CFA_expression: expression, + DW_CFA_offset_extended_sf: offsetextendedsf, + DW_CFA_def_cfa_sf: defcfasf, + DW_CFA_def_cfa_offset_sf: defcfaoffsetsf, + DW_CFA_val_offset: valoffset, + DW_CFA_val_offset_sf: valoffsetsf, + DW_CFA_val_expression: valexpression, + DW_CFA_lo_user: louser, + DW_CFA_hi_user: hiuser, +} + +func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext { + initialInstructions := make([]byte, len(cie.InitialInstructions)) + copy(initialInstructions, cie.InitialInstructions) + frame := &FrameContext{ + cie: cie, + regs: make(map[uint64]DWRule), + initialRegs: make(map[uint64]DWRule), + prevRegs: make(map[uint64]DWRule), + codeAlignment: cie.CodeAlignmentFactor, + dataAlignment: cie.DataAlignmentFactor, + buf: bytes.NewBuffer(initialInstructions), + } + + frame.ExecuteDwarfProgram() + return frame +} + +// Unwind the stack to find the return address register. +func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameContext { + frame := executeCIEInstructions(fde.CIE) + frame.order = fde.order + frame.loc = fde.Begin() + frame.address = pc + fdeInstructions := make([]byte, len(fde.Instructions)) + copy(fdeInstructions, fde.Instructions) + frame.ExecuteUntilPC(fdeInstructions) + + return frame +} + +func (frame *FrameContext) ExecuteDwarfProgram() { + for frame.buf.Len() > 0 { + executeDwarfInstruction(frame) + } +} + +// Execute dwarf instructions. +func (frame *FrameContext) ExecuteUntilPC(instructions []byte) { + frame.buf.Truncate(0) + frame.buf.Write(instructions) + + // We only need to execute the instructions until + // ctx.loc > ctx.addess (which is the address we + // are currently at in the traced process). + for frame.address >= frame.loc && frame.buf.Len() > 0 { + executeDwarfInstruction(frame) + } +} + +func executeDwarfInstruction(frame *FrameContext) { + instruction, err := frame.buf.ReadByte() + if err != nil { + panic("Could not read from instruction buffer") + } + + if instruction == DW_CFA_nop { + return + } + + fn := lookupFunc(instruction, frame.buf) + + fn(frame) +} + +func lookupFunc(instruction byte, buf *bytes.Buffer) instruction { + const high_2_bits = 0xc0 + var restore bool + + // Special case the 3 opcodes that have their argument encoded in the opcode itself. + switch instruction & high_2_bits { + case DW_CFA_advance_loc: + instruction = DW_CFA_advance_loc + restore = true + + case DW_CFA_offset: + instruction = DW_CFA_offset + restore = true + + case DW_CFA_restore: + instruction = DW_CFA_restore + restore = true + } + + if restore { + // Restore the last byte as it actually contains the argument for the opcode. + err := buf.UnreadByte() + if err != nil { + panic("Could not unread byte") + } + } + + fn, ok := fnlookup[instruction] + if !ok { + panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction)) + } + + return fn +} + +func advanceloc(frame *FrameContext) { + b, err := frame.buf.ReadByte() + if err != nil { + panic("Could not read byte") + } + + delta := b & low_6_offset + frame.loc += uint64(delta) * frame.codeAlignment +} + +func advanceloc1(frame *FrameContext) { + delta, err := frame.buf.ReadByte() + if err != nil { + panic("Could not read byte") + } + + frame.loc += uint64(delta) * frame.codeAlignment +} + +func advanceloc2(frame *FrameContext) { + var delta uint16 + binary.Read(frame.buf, frame.order, &delta) + + frame.loc += uint64(delta) * frame.codeAlignment +} + +func advanceloc4(frame *FrameContext) { + var delta uint32 + binary.Read(frame.buf, frame.order, &delta) + + frame.loc += uint64(delta) * frame.codeAlignment +} + +func offset(frame *FrameContext) { + b, err := frame.buf.ReadByte() + if err != nil { + panic(err) + } + + var ( + reg = b & low_6_offset + offset, _ = util.DecodeULEB128(frame.buf) + ) + + frame.regs[uint64(reg)] = DWRule{offset: int64(offset) * frame.dataAlignment, rule: rule_offset} +} + +func restore(frame *FrameContext) { + b, err := frame.buf.ReadByte() + if err != nil { + panic(err) + } + + reg := uint64(b & low_6_offset) + oldrule, ok := frame.initialRegs[reg] + if ok { + frame.regs[reg] = DWRule{offset: oldrule.offset, rule: rule_offset} + } else { + frame.regs[reg] = DWRule{rule: rule_undefined} + } +} + +func setloc(frame *FrameContext) { + var loc uint64 + binary.Read(frame.buf, frame.order, &loc) + + frame.loc = loc +} + +func offsetextended(frame *FrameContext) { + var ( + reg, _ = util.DecodeULEB128(frame.buf) + offset, _ = util.DecodeULEB128(frame.buf) + ) + + frame.regs[reg] = DWRule{offset: int64(offset) * frame.dataAlignment, rule: rule_offset} +} + +func undefined(frame *FrameContext) { + reg, _ := util.DecodeULEB128(frame.buf) + frame.regs[reg] = DWRule{rule: rule_undefined} +} + +func samevalue(frame *FrameContext) { + reg, _ := util.DecodeULEB128(frame.buf) + frame.regs[reg] = DWRule{rule: rule_sameval} +} + +func register(frame *FrameContext) { + reg1, _ := util.DecodeULEB128(frame.buf) + reg2, _ := util.DecodeULEB128(frame.buf) + frame.regs[reg1] = DWRule{newreg: reg2, rule: rule_register} +} + +func rememberstate(frame *FrameContext) { + frame.prevRegs = frame.regs +} + +func restorestate(frame *FrameContext) { + frame.regs = frame.prevRegs +} + +func restoreextended(frame *FrameContext) { + reg, _ := util.DecodeULEB128(frame.buf) + + oldrule, ok := frame.initialRegs[reg] + if ok { + frame.regs[reg] = DWRule{offset: oldrule.offset, rule: rule_offset} + } else { + frame.regs[reg] = DWRule{rule: rule_undefined} + } +} + +func defcfa(frame *FrameContext) { + reg, _ := util.DecodeULEB128(frame.buf) + offset, _ := util.DecodeULEB128(frame.buf) + + frame.cfa.register = reg + frame.cfa.offset = int64(offset) +} + +func defcfaregister(frame *FrameContext) { + reg, _ := util.DecodeULEB128(frame.buf) + frame.cfa.register = reg +} + +func defcfaoffset(frame *FrameContext) { + offset, _ := util.DecodeULEB128(frame.buf) + frame.cfa.offset = int64(offset) +} + +func defcfasf(frame *FrameContext) { + reg, _ := util.DecodeULEB128(frame.buf) + offset, _ := util.DecodeSLEB128(frame.buf) + + frame.cfa.register = reg + frame.cfa.offset = offset * frame.dataAlignment +} + +func defcfaoffsetsf(frame *FrameContext) { + offset, _ := util.DecodeSLEB128(frame.buf) + offset *= frame.dataAlignment + frame.cfa.offset = offset +} + +func defcfaexpression(frame *FrameContext) { + var ( + l, _ = util.DecodeULEB128(frame.buf) + expr = frame.buf.Next(int(l)) + ) + + frame.cfa.expression = expr + frame.cfa.rule = rule_expression +} + +func expression(frame *FrameContext) { + var ( + reg, _ = util.DecodeULEB128(frame.buf) + l, _ = util.DecodeULEB128(frame.buf) + expr = frame.buf.Next(int(l)) + ) + + frame.regs[reg] = DWRule{rule: rule_expression, expression: expr} +} + +func offsetextendedsf(frame *FrameContext) { + var ( + reg, _ = util.DecodeULEB128(frame.buf) + offset, _ = util.DecodeSLEB128(frame.buf) + ) + + frame.regs[reg] = DWRule{offset: offset * frame.dataAlignment, rule: rule_offset} +} + +func valoffset(frame *FrameContext) { + var ( + reg, _ = util.DecodeULEB128(frame.buf) + offset, _ = util.DecodeULEB128(frame.buf) + ) + + frame.regs[reg] = DWRule{offset: int64(offset), rule: rule_valoffset} +} + +func valoffsetsf(frame *FrameContext) { + var ( + reg, _ = util.DecodeULEB128(frame.buf) + offset, _ = util.DecodeSLEB128(frame.buf) + ) + + frame.regs[reg] = DWRule{offset: offset * frame.dataAlignment, rule: rule_valoffset} +} + +func valexpression(frame *FrameContext) { + var ( + reg, _ = util.DecodeULEB128(frame.buf) + l, _ = util.DecodeULEB128(frame.buf) + expr = frame.buf.Next(int(l)) + ) + + frame.regs[reg] = DWRule{rule: rule_valexpression, expression: expr} +} + +func louser(frame *FrameContext) { + frame.buf.Next(1) +} + +func hiuser(frame *FrameContext) { + frame.buf.Next(1) +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/line/line_parser.go b/vendor/github.com/derekparker/delve/pkg/dwarf/line/line_parser.go new file mode 100644 index 0000000..0d3677f --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/line/line_parser.go @@ -0,0 +1,122 @@ +package line + +import ( + "bytes" + "encoding/binary" + + "github.com/derekparker/delve/pkg/dwarf/util" +) + +type DebugLinePrologue struct { + UnitLength uint32 + Version uint16 + Length uint32 + MinInstrLength uint8 + InitialIsStmt uint8 + LineBase int8 + LineRange uint8 + OpcodeBase uint8 + StdOpLengths []uint8 +} + +type DebugLineInfo struct { + Prologue *DebugLinePrologue + IncludeDirs []string + FileNames []*FileEntry + Instructions []byte + Lookup map[string]*FileEntry +} + +type FileEntry struct { + Name string + DirIdx uint64 + LastModTime uint64 + Length uint64 +} + +type DebugLines []*DebugLineInfo + +func (d *DebugLines) GetLineInfo(name string) *DebugLineInfo { + // Find in which table file exists and return it. + for _, l := range *d { + if _, ok := l.Lookup[name]; ok { + return l + } + } + return nil +} + +func Parse(data []byte) DebugLines { + var ( + lines = make(DebugLines, 0) + buf = bytes.NewBuffer(data) + ) + + // We have to parse multiple file name tables here. + for buf.Len() > 0 { + dbl := new(DebugLineInfo) + dbl.Lookup = make(map[string]*FileEntry) + + parseDebugLinePrologue(dbl, buf) + parseIncludeDirs(dbl, buf) + parseFileEntries(dbl, buf) + + // Instructions size calculation breakdown: + // - dbl.Prologue.UnitLength is the length of the entire unit, not including the 4 bytes to represent that length. + // - dbl.Prologue.Length is the length of the prologue not including unit length, version or prologue length itself. + // - So you have UnitLength - PrologueLength - (version_length_bytes(2) + prologue_length_bytes(4)). + dbl.Instructions = buf.Next(int(dbl.Prologue.UnitLength - dbl.Prologue.Length - 6)) + + lines = append(lines, dbl) + } + + return lines +} + +func parseDebugLinePrologue(dbl *DebugLineInfo, buf *bytes.Buffer) { + p := new(DebugLinePrologue) + + p.UnitLength = binary.LittleEndian.Uint32(buf.Next(4)) + p.Version = binary.LittleEndian.Uint16(buf.Next(2)) + p.Length = binary.LittleEndian.Uint32(buf.Next(4)) + p.MinInstrLength = uint8(buf.Next(1)[0]) + p.InitialIsStmt = uint8(buf.Next(1)[0]) + p.LineBase = int8(buf.Next(1)[0]) + p.LineRange = uint8(buf.Next(1)[0]) + p.OpcodeBase = uint8(buf.Next(1)[0]) + + p.StdOpLengths = make([]uint8, p.OpcodeBase-1) + binary.Read(buf, binary.LittleEndian, &p.StdOpLengths) + + dbl.Prologue = p +} + +func parseIncludeDirs(info *DebugLineInfo, buf *bytes.Buffer) { + for { + str, _ := util.ParseString(buf) + if str == "" { + break + } + + info.IncludeDirs = append(info.IncludeDirs, str) + } +} + +func parseFileEntries(info *DebugLineInfo, buf *bytes.Buffer) { + for { + entry := new(FileEntry) + + name, _ := util.ParseString(buf) + if name == "" { + break + } + + entry.Name = name + entry.DirIdx, _ = util.DecodeULEB128(buf) + entry.LastModTime, _ = util.DecodeULEB128(buf) + entry.Length, _ = util.DecodeULEB128(buf) + + info.FileNames = append(info.FileNames, entry) + info.Lookup[name] = entry + } +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/line/state_machine.go b/vendor/github.com/derekparker/delve/pkg/dwarf/line/state_machine.go new file mode 100644 index 0000000..feedd4e --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/line/state_machine.go @@ -0,0 +1,267 @@ +package line + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + + "github.com/derekparker/delve/pkg/dwarf/util" +) + +type Location struct { + File string + Line int + Address uint64 + Delta int +} + +type StateMachine struct { + dbl *DebugLineInfo + file string + line int + address uint64 + column uint + isStmt bool + basicBlock bool + endSeq bool + lastWasStandard bool + lastDelta int + // valid is true if the current value of the state machine is the address of + // an instruction (using the terminology used by DWARF spec the current + // value of the state machine should be appended to the matrix representing + // the compilation unit) + valid bool +} + +type opcodefn func(*StateMachine, *bytes.Buffer) + +// Special opcodes +const ( + DW_LNS_copy = 1 + DW_LNS_advance_pc = 2 + DW_LNS_advance_line = 3 + DW_LNS_set_file = 4 + DW_LNS_set_column = 5 + DW_LNS_negate_stmt = 6 + DW_LNS_set_basic_block = 7 + DW_LNS_const_add_pc = 8 + DW_LNS_fixed_advance_pc = 9 +) + +// Extended opcodes +const ( + DW_LINE_end_sequence = 1 + DW_LINE_set_address = 2 + DW_LINE_define_file = 3 +) + +var standardopcodes = map[byte]opcodefn{ + DW_LNS_copy: copyfn, + DW_LNS_advance_pc: advancepc, + DW_LNS_advance_line: advanceline, + DW_LNS_set_file: setfile, + DW_LNS_set_column: setcolumn, + DW_LNS_negate_stmt: negatestmt, + DW_LNS_set_basic_block: setbasicblock, + DW_LNS_const_add_pc: constaddpc, + DW_LNS_fixed_advance_pc: fixedadvancepc, +} + +var extendedopcodes = map[byte]opcodefn{ + DW_LINE_end_sequence: endsequence, + DW_LINE_set_address: setaddress, + DW_LINE_define_file: definefile, +} + +func newStateMachine(dbl *DebugLineInfo) *StateMachine { + return &StateMachine{dbl: dbl, file: dbl.FileNames[0].Name, line: 1} +} + +// Returns all PCs for a given file/line. Useful for loops where the 'for' line +// could be split amongst 2 PCs. +func (dbl *DebugLines) AllPCsForFileLine(f string, l int) (pcs []uint64) { + var ( + foundFile bool + lastAddr uint64 + lineInfo = dbl.GetLineInfo(f) + sm = newStateMachine(lineInfo) + buf = bytes.NewBuffer(lineInfo.Instructions) + ) + + for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() { + findAndExecOpcode(sm, buf, b) + if foundFile && sm.file != f { + return + } + if sm.line == l && sm.file == f && sm.address != lastAddr { + foundFile = true + if sm.valid { + pcs = append(pcs, sm.address) + } + line := sm.line + // Keep going until we're on a different line. We only care about + // when a line comes back around (i.e. for loop) so get to next line, + // and try to find the line we care about again. + for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() { + findAndExecOpcode(sm, buf, b) + if line < sm.line { + break + } + } + } + } + return +} + +var NoSourceError = errors.New("no source available") + +func (dbl *DebugLines) AllPCsBetween(begin, end uint64, filename string) ([]uint64, error) { + lineInfo := dbl.GetLineInfo(filename) + if lineInfo == nil { + return nil, NoSourceError + } + var ( + pcs []uint64 + lastaddr uint64 + sm = newStateMachine(lineInfo) + buf = bytes.NewBuffer(lineInfo.Instructions) + ) + + for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() { + findAndExecOpcode(sm, buf, b) + if !sm.valid { + continue + } + if sm.address > end { + break + } + if sm.address >= begin && sm.address > lastaddr { + lastaddr = sm.address + pcs = append(pcs, sm.address) + } + } + return pcs, nil +} + +func findAndExecOpcode(sm *StateMachine, buf *bytes.Buffer, b byte) { + switch { + case b == 0: + execExtendedOpcode(sm, b, buf) + case b < sm.dbl.Prologue.OpcodeBase: + execStandardOpcode(sm, b, buf) + default: + execSpecialOpcode(sm, b) + } +} + +func execSpecialOpcode(sm *StateMachine, instr byte) { + var ( + opcode = uint8(instr) + decoded = opcode - sm.dbl.Prologue.OpcodeBase + ) + + if sm.dbl.Prologue.InitialIsStmt == uint8(1) { + sm.isStmt = true + } + + sm.lastDelta = int(sm.dbl.Prologue.LineBase + int8(decoded%sm.dbl.Prologue.LineRange)) + sm.line += sm.lastDelta + sm.address += uint64(decoded/sm.dbl.Prologue.LineRange) * uint64(sm.dbl.Prologue.MinInstrLength) + sm.basicBlock = false + sm.lastWasStandard = false + sm.valid = true +} + +func execExtendedOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) { + _, _ = util.DecodeULEB128(buf) + b, _ := buf.ReadByte() + fn, ok := extendedopcodes[b] + if !ok { + panic(fmt.Sprintf("Encountered unknown extended opcode %#v\n", b)) + } + sm.lastWasStandard = false + sm.valid = false + + fn(sm, buf) +} + +func execStandardOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) { + fn, ok := standardopcodes[instr] + if !ok { + panic(fmt.Sprintf("Encountered unknown standard opcode %#v\n", instr)) + } + sm.lastWasStandard = true + sm.valid = false + + fn(sm, buf) +} + +func copyfn(sm *StateMachine, buf *bytes.Buffer) { + sm.basicBlock = false + sm.valid = true +} + +func advancepc(sm *StateMachine, buf *bytes.Buffer) { + addr, _ := util.DecodeULEB128(buf) + sm.address += addr * uint64(sm.dbl.Prologue.MinInstrLength) +} + +func advanceline(sm *StateMachine, buf *bytes.Buffer) { + line, _ := util.DecodeSLEB128(buf) + sm.line += int(line) + sm.lastDelta = int(line) +} + +func setfile(sm *StateMachine, buf *bytes.Buffer) { + i, _ := util.DecodeULEB128(buf) + sm.file = sm.dbl.FileNames[i-1].Name +} + +func setcolumn(sm *StateMachine, buf *bytes.Buffer) { + c, _ := util.DecodeULEB128(buf) + sm.column = uint(c) +} + +func negatestmt(sm *StateMachine, buf *bytes.Buffer) { + sm.isStmt = !sm.isStmt +} + +func setbasicblock(sm *StateMachine, buf *bytes.Buffer) { + sm.basicBlock = true +} + +func constaddpc(sm *StateMachine, buf *bytes.Buffer) { + sm.address += uint64((255-sm.dbl.Prologue.OpcodeBase)/sm.dbl.Prologue.LineRange) * uint64(sm.dbl.Prologue.MinInstrLength) +} + +func fixedadvancepc(sm *StateMachine, buf *bytes.Buffer) { + var operand uint16 + binary.Read(buf, binary.LittleEndian, &operand) + + sm.address += uint64(operand) +} + +func endsequence(sm *StateMachine, buf *bytes.Buffer) { + sm.endSeq = true + sm.valid = true +} + +func setaddress(sm *StateMachine, buf *bytes.Buffer) { + var addr uint64 + + binary.Read(buf, binary.LittleEndian, &addr) + + sm.address = addr +} + +func definefile(sm *StateMachine, buf *bytes.Buffer) { + var ( + _, _ = util.ParseString(buf) + _, _ = util.DecodeULEB128(buf) + _, _ = util.DecodeULEB128(buf) + _, _ = util.DecodeULEB128(buf) + ) + + // Don't do anything here yet. +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/op/op.go b/vendor/github.com/derekparker/delve/pkg/dwarf/op/op.go new file mode 100644 index 0000000..158b073 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/op/op.go @@ -0,0 +1,84 @@ +package op + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + + "github.com/derekparker/delve/pkg/dwarf/util" +) + +const ( + DW_OP_addr = 0x3 + DW_OP_call_frame_cfa = 0x9c + DW_OP_plus = 0x22 + DW_OP_consts = 0x11 + DW_OP_plus_uconsts = 0x23 +) + +type stackfn func(*bytes.Buffer, []int64, int64) ([]int64, error) + +var oplut = map[byte]stackfn{ + DW_OP_call_frame_cfa: callframecfa, + DW_OP_plus: plus, + DW_OP_consts: consts, + DW_OP_addr: addr, + DW_OP_plus_uconsts: plusuconsts, +} + +func ExecuteStackProgram(cfa int64, instructions []byte) (int64, error) { + stack := make([]int64, 0, 3) + buf := bytes.NewBuffer(instructions) + + for opcode, err := buf.ReadByte(); err == nil; opcode, err = buf.ReadByte() { + fn, ok := oplut[opcode] + if !ok { + return 0, fmt.Errorf("invalid instruction %#v", opcode) + } + + stack, err = fn(buf, stack, cfa) + if err != nil { + return 0, err + } + } + + if len(stack) == 0 { + return 0, errors.New("empty OP stack") + } + + return stack[len(stack)-1], nil +} + +func callframecfa(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) { + if cfa == 0 { + return stack, fmt.Errorf("Could not retrieve CFA for current PC") + } + return append(stack, int64(cfa)), nil +} + +func addr(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) { + return append(stack, int64(binary.LittleEndian.Uint64(buf.Next(8)))), nil +} + +func plus(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) { + var ( + slen = len(stack) + digits = stack[slen-2 : slen] + st = stack[:slen-2] + ) + + return append(st, digits[0]+digits[1]), nil +} + +func plusuconsts(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) { + slen := len(stack) + num, _ := util.DecodeULEB128(buf) + stack[slen-1] = stack[slen-1] + int64(num) + return stack, nil +} + +func consts(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) { + num, _ := util.DecodeSLEB128(buf) + return append(stack, num), nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/reader/reader.go b/vendor/github.com/derekparker/delve/pkg/dwarf/reader/reader.go new file mode 100755 index 0000000..ecd61f5 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/reader/reader.go @@ -0,0 +1,345 @@ +package reader + +import ( + "errors" + "fmt" + + "github.com/derekparker/delve/pkg/dwarf/op" + "golang.org/x/debug/dwarf" +) + +type Reader struct { + *dwarf.Reader + depth int +} + +// New returns a reader for the specified dwarf data. +func New(data *dwarf.Data) *Reader { + return &Reader{data.Reader(), 0} +} + +// Seek moves the reader to an arbitrary offset. +func (reader *Reader) Seek(off dwarf.Offset) { + reader.depth = 0 + reader.Reader.Seek(off) +} + +// SeekToEntry moves the reader to an arbitrary entry. +func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error { + reader.Seek(entry.Offset) + // Consume the current entry so .Next works as intended + _, err := reader.Next() + return err +} + +// SeekToFunctionEntry moves the reader to the function that includes the +// specified program counter. +func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) { + reader.Seek(0) + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + if entry.Tag != dwarf.TagSubprogram { + continue + } + + lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64) + if !ok { + continue + } + + highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64) + if !ok { + continue + } + + if lowpc <= pc && highpc > pc { + return entry, nil + } + } + + return nil, fmt.Errorf("unable to find function context") +} + +// Returns the address for the named entry. +func (reader *Reader) AddrFor(name string) (uint64, error) { + entry, err := reader.FindEntryNamed(name, false) + if err != nil { + return 0, err + } + instructions, ok := entry.Val(dwarf.AttrLocation).([]byte) + if !ok { + return 0, fmt.Errorf("type assertion failed") + } + addr, err := op.ExecuteStackProgram(0, instructions) + if err != nil { + return 0, err + } + return uint64(addr), nil +} + +// Returns the address for the named struct member. Expects the reader to be at the parent entry +// or one of the parents children, thus does not seek to parent by itself. +func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) { + for { + entry, err := reader.NextMemberVariable() + if err != nil { + return 0, err + } + if entry == nil { + return 0, fmt.Errorf("nil entry for member named %s", member) + } + name, ok := entry.Val(dwarf.AttrName).(string) + if !ok || name != member { + continue + } + instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte) + if !ok { + continue + } + addr, err := op.ExecuteStackProgram(0, append(initialInstructions, instructions...)) + return uint64(addr), err + } +} + +var TypeNotFoundErr = errors.New("no type entry found, use 'types' for a list of valid types") + +// SeekToType moves the reader to the type specified by the entry, +// optionally resolving typedefs and pointer types. If the reader is set +// to a struct type the NextMemberVariable call can be used to walk all member data. +func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) { + offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset) + if !ok { + return nil, fmt.Errorf("entry does not have a type attribute") + } + + // Seek to the first type offset + reader.Seek(offset) + + // Walk the types to the base + for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() { + if err != nil { + return nil, err + } + + if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs { + return typeEntry, nil + } + + if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes { + return typeEntry, nil + } + + offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset) + if !ok { + return typeEntry, nil + } + + reader.Seek(offset) + } + + return nil, TypeNotFoundErr +} + +func (reader *Reader) NextType() (*dwarf.Entry, error) { + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + switch entry.Tag { + case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType: + return entry, nil + } + } + + return nil, nil +} + +// SeekToTypeNamed moves the reader to the type specified by the name. +// If the reader is set to a struct type the NextMemberVariable call +// can be used to walk all member data. +func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) { + // Walk the types to the base + for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() { + if err != nil { + return nil, err + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + + if n == name { + return entry, nil + } + } + + return nil, TypeNotFoundErr +} + +// Finds the entry for 'name'. +func (reader *Reader) FindEntryNamed(name string, member bool) (*dwarf.Entry, error) { + depth := 1 + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + if entry.Children { + depth++ + } + + if entry.Tag == 0 { + depth-- + if depth <= 0 { + return nil, fmt.Errorf("could not find symbol value for %s", name) + } + } + + if member { + if entry.Tag != dwarf.TagMember { + continue + } + } else { + if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagStructType { + continue + } + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok || n != name { + continue + } + return entry, nil + } + return nil, fmt.Errorf("could not find symbol value for %s", name) +} + +func (reader *Reader) InstructionsForEntryNamed(name string, member bool) ([]byte, error) { + entry, err := reader.FindEntryNamed(name, member) + if err != nil { + return nil, err + } + var attr dwarf.Attr + if member { + attr = dwarf.AttrDataMemberLoc + } else { + attr = dwarf.AttrLocation + } + instr, ok := entry.Val(attr).([]byte) + if !ok { + return nil, errors.New("invalid typecast for Dwarf instructions") + } + return instr, nil +} + +func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) { + if entry.Tag == dwarf.TagMember { + instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte) + if !ok { + return nil, fmt.Errorf("member data has no data member location attribute") + } + // clone slice to prevent stomping on the dwarf data + return append([]byte{}, instructions...), nil + } + + // non-member + instructions, ok := entry.Val(dwarf.AttrLocation).([]byte) + if !ok { + return nil, fmt.Errorf("entry has no location attribute") + } + + // clone slice to prevent stomping on the dwarf data + return append([]byte{}, instructions...), nil +} + +// NextScopeVariable moves the reader to the next debug entry that describes a local variable and returns the entry. +func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) { + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + // All scope variables will be at the same depth + reader.SkipChildren() + + // End of the current depth + if entry.Tag == 0 { + break + } + + if entry.Tag == dwarf.TagVariable || entry.Tag == dwarf.TagFormalParameter { + return entry, nil + } + } + + // No more items + return nil, nil +} + +// NextMememberVariable moves the reader to the next debug entry that describes a member variable and returns the entry. +func (reader *Reader) NextMemberVariable() (*dwarf.Entry, error) { + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + // All member variables will be at the same depth + reader.SkipChildren() + + // End of the current depth + if entry.Tag == 0 { + break + } + + if entry.Tag == dwarf.TagMember { + return entry, nil + } + } + + // No more items + return nil, nil +} + +// NextPackageVariable moves the reader to the next debug entry that describes a package variable. +// Any TagVariable entry that is not inside a sub prgram entry and is marked external is considered a package variable. +func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) { + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + if entry.Tag == dwarf.TagVariable { + ext, ok := entry.Val(dwarf.AttrExternal).(bool) + if ok && ext { + return entry, nil + } + } + + // Ignore everything inside sub programs + if entry.Tag == dwarf.TagSubprogram { + reader.SkipChildren() + } + } + + // No more items + return nil, nil +} + +func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) { + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return nil, err + } + + if entry.Tag == dwarf.TagCompileUnit { + return entry, nil + } + } + + return nil, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/dwarf/util/util.go b/vendor/github.com/derekparker/delve/pkg/dwarf/util/util.go new file mode 100644 index 0000000..f60c203 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/dwarf/util/util.go @@ -0,0 +1,81 @@ +package util + +import "bytes" + +// DecodeULEB128 decodes an unsigned Little Endian Base 128 +// represented number. +func DecodeULEB128(buf *bytes.Buffer) (uint64, uint32) { + var ( + result uint64 + shift uint64 + length uint32 + ) + + if buf.Len() == 0 { + return 0, 0 + } + + for { + b, err := buf.ReadByte() + if err != nil { + panic("Could not parse ULEB128 value") + } + length++ + + result |= uint64((uint(b) & 0x7f) << shift) + + // If high order bit is 1. + if b&0x80 == 0 { + break + } + + shift += 7 + } + + return result, length +} + +// DecodeSLEB128 decodes a signed Little Endian Base 128 +// represented number. +func DecodeSLEB128(buf *bytes.Buffer) (int64, uint32) { + var ( + b byte + err error + result int64 + shift uint64 + length uint32 + ) + + if buf.Len() == 0 { + return 0, 0 + } + + for { + b, err = buf.ReadByte() + if err != nil { + panic("Could not parse SLEB128 value") + } + length++ + + result |= int64((int64(b) & 0x7f) << shift) + shift += 7 + if b&0x80 == 0 { + break + } + } + + if (shift < 8*uint64(length)) && (b&0x40 > 0) { + result |= -(1 << shift) + } + + return result, length +} + +func ParseString(data *bytes.Buffer) (string, uint32) { + str, err := data.ReadString(0x0) + if err != nil { + panic("Could not parse string") + } + + return str[:len(str)-1], uint32(len(str)) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/arch.go b/vendor/github.com/derekparker/delve/pkg/proc/arch.go new file mode 100644 index 0000000..4031fd8 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/arch.go @@ -0,0 +1,79 @@ +package proc + +import "runtime" + +// Arch defines an interface for representing a +// CPU architecture. +type Arch interface { + SetGStructOffset(ver GoVersion, iscgo bool) + PtrSize() int + BreakpointInstruction() []byte + BreakpointSize() int + GStructOffset() uint64 +} + +// AMD64 represents the AMD64 CPU architecture. +type AMD64 struct { + ptrSize int + breakInstruction []byte + breakInstructionLen int + gStructOffset uint64 + hardwareBreakpointUsage []bool +} + +// AMD64Arch returns an initialized AMD64 +// struct. +func AMD64Arch() *AMD64 { + var breakInstr = []byte{0xCC} + + return &AMD64{ + ptrSize: 8, + breakInstruction: breakInstr, + breakInstructionLen: len(breakInstr), + hardwareBreakpointUsage: make([]bool, 4), + } +} + +// SetGStructOffset sets the offset of the G struct on the AMD64 +// arch struct. The offset is dependent on the Go compiler Version +// and whether or not the target program was externally linked. +func (a *AMD64) SetGStructOffset(ver GoVersion, isextld bool) { + switch runtime.GOOS { + case "darwin": + a.gStructOffset = 0x8a0 + case "linux": + a.gStructOffset = 0xfffffffffffffff0 + if isextld || ver.AfterOrEqual(GoVersion{1, 5, -1, 2, 0}) || ver.IsDevel() { + a.gStructOffset += 8 + } + case "windows": + // Use ArbitraryUserPointer (0x28) as pointer to pointer + // to G struct per: + // https://golang.org/src/runtime/cgo/gcc_windows_amd64.c + a.gStructOffset = 0x28 + } +} + +// PtrSize returns the size of a pointer +// on this architecture. +func (a *AMD64) PtrSize() int { + return a.ptrSize +} + +// BreakpointInstruction returns the Breakpoint +// instruction for this architecture. +func (a *AMD64) BreakpointInstruction() []byte { + return a.breakInstruction +} + +// BreakpointSize returns the size of the +// breakpoint instruction on this architecture. +func (a *AMD64) BreakpointSize() int { + return a.breakInstructionLen +} + +// GStructOffset returns the offset of the G +// struct in thread local storage. +func (a *AMD64) GStructOffset() uint64 { + return a.gStructOffset +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/breakpoints.go b/vendor/github.com/derekparker/delve/pkg/proc/breakpoints.go new file mode 100644 index 0000000..8f13d47 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/breakpoints.go @@ -0,0 +1,163 @@ +package proc + +import ( + "errors" + "fmt" + "go/ast" + "go/constant" + "reflect" +) + +// Breakpoint represents a breakpoint. Stores information on the break +// point including the byte of data that originally was stored at that +// address. +type Breakpoint struct { + // File & line information for printing. + FunctionName string + File string + Line int + + Addr uint64 // Address breakpoint is set for. + OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction. + Name string // User defined name of the breakpoint + ID int // Monotonically increasing ID. + Kind BreakpointKind // Whether this is an internal breakpoint (for next'ing or stepping). + + // Breakpoint information + Tracepoint bool // Tracepoint flag + Goroutine bool // Retrieve goroutine information + Stacktrace int // Number of stack frames to retrieve + Variables []string // Variables to evaluate + LoadArgs *LoadConfig + LoadLocals *LoadConfig + HitCount map[int]uint64 // Number of times a breakpoint has been reached in a certain goroutine + TotalHitCount uint64 // Number of times a breakpoint has been reached + + // DeferReturns: when kind == NextDeferBreakpoint this breakpoint + // will also check if the caller is runtime.gopanic or if the return + // address is in the DeferReturns array. + // Next uses NextDeferBreakpoints for the breakpoint it sets on the + // deferred function, DeferReturns is populated with the + // addresses of calls to runtime.deferreturn in the current + // function. This insures that the breakpoint on the deferred + // function only triggers on panic or on the defer call to + // the function, not when the function is called directly + DeferReturns []uint64 + // Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true + Cond ast.Expr +} + +// Breakpoint Kind determines the behavior of delve when the +// breakpoint is reached. +type BreakpointKind int + +const ( + // UserBreakpoint is a user set breakpoint + UserBreakpoint BreakpointKind = iota + // NextBreakpoint is a breakpoint set by Next, Continue + // will stop on it and delete it + NextBreakpoint + // NextDeferBreakpoint is a breakpoint set by Next on the + // first deferred function. In addition to checking their condition + // breakpoints of this kind will also check that the function has been + // called by runtime.gopanic or through runtime.deferreturn. + NextDeferBreakpoint + // StepBreakpoint is a breakpoint set by Step on a CALL instruction, + // Continue will set a new breakpoint (of NextBreakpoint kind) on the + // destination of CALL, delete this breakpoint and then continue again + StepBreakpoint +) + +func (bp *Breakpoint) String() string { + return fmt.Sprintf("Breakpoint %d at %#v %s:%d (%d)", bp.ID, bp.Addr, bp.File, bp.Line, bp.TotalHitCount) +} + +// Clear this breakpoint appropriately depending on whether it is a +// hardware or software breakpoint. +func (bp *Breakpoint) Clear(thread *Thread) (*Breakpoint, error) { + if _, err := thread.writeMemory(uintptr(bp.Addr), bp.OriginalData); err != nil { + return nil, fmt.Errorf("could not clear breakpoint %s", err) + } + return bp, nil +} + +// BreakpointExistsError is returned when trying to set a breakpoint at +// an address that already has a breakpoint set for it. +type BreakpointExistsError struct { + file string + line int + addr uint64 +} + +func (bpe BreakpointExistsError) Error() string { + return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr) +} + +// InvalidAddressError represents the result of +// attempting to set a breakpoint at an invalid address. +type InvalidAddressError struct { + address uint64 +} + +func (iae InvalidAddressError) Error() string { + return fmt.Sprintf("Invalid address %#v\n", iae.address) +} + +func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error { + _, err := thread.writeMemory(uintptr(addr), dbp.arch.BreakpointInstruction()) + return err +} + +func (bp *Breakpoint) checkCondition(thread *Thread) (bool, error) { + if bp.Cond == nil { + return true, nil + } + if bp.Kind == NextDeferBreakpoint { + frames, err := thread.Stacktrace(2) + if err == nil { + ispanic := len(frames) >= 3 && frames[2].Current.Fn != nil && frames[2].Current.Fn.Name == "runtime.gopanic" + isdeferreturn := false + if len(frames) >= 1 { + for _, pc := range bp.DeferReturns { + if frames[0].Ret == pc { + isdeferreturn = true + break + } + } + } + if !ispanic && !isdeferreturn { + return false, nil + } + } + } + scope, err := thread.Scope() + if err != nil { + return true, err + } + v, err := scope.evalAST(bp.Cond) + if err != nil { + return true, fmt.Errorf("error evaluating expression: %v", err) + } + if v.Unreadable != nil { + return true, fmt.Errorf("condition expression unreadable: %v", v.Unreadable) + } + if v.Kind != reflect.Bool { + return true, errors.New("condition expression not boolean") + } + return constant.BoolVal(v.Value), nil +} + +// Internal returns true for breakpoints not set directly by the user. +func (bp *Breakpoint) Internal() bool { + return bp.Kind != UserBreakpoint +} + +// NoBreakpointError is returned when trying to +// clear a breakpoint that does not exist. +type NoBreakpointError struct { + addr uint64 +} + +func (nbp NoBreakpointError) Error() string { + return fmt.Sprintf("no breakpoint at %#v", nbp.addr) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/disasm.go b/vendor/github.com/derekparker/delve/pkg/proc/disasm.go new file mode 100644 index 0000000..731336e --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/disasm.go @@ -0,0 +1,67 @@ +package proc + +type AsmInstruction struct { + Loc Location + DestLoc *Location + Bytes []byte + Breakpoint bool + AtPC bool + Inst *ArchInst +} + +type AssemblyFlavour int + +const ( + GNUFlavour = AssemblyFlavour(iota) + IntelFlavour +) + +// Disassemble disassembles target memory between startPC and endPC +// If currentGoroutine is set and thread is stopped at a CALL instruction Disassemble will evaluate the argument of the CALL instruction using the thread's registers +// Be aware that the Bytes field of each returned instruction is a slice of a larger array of size endPC - startPC +func (thread *Thread) Disassemble(startPC, endPC uint64, currentGoroutine bool) ([]AsmInstruction, error) { + if thread.dbp.exited { + return nil, &ProcessExitedError{} + } + mem, err := thread.readMemory(uintptr(startPC), int(endPC-startPC)) + if err != nil { + return nil, err + } + + r := make([]AsmInstruction, 0, len(mem)/15) + pc := startPC + + var curpc uint64 + var regs Registers + if currentGoroutine { + regs, _ = thread.Registers(false) + if regs != nil { + curpc = regs.PC() + } + } + + for len(mem) > 0 { + bp, atbp := thread.dbp.breakpoints[pc] + if atbp { + for i := range bp.OriginalData { + mem[i] = bp.OriginalData[i] + } + } + file, line, fn := thread.dbp.PCToLine(pc) + loc := Location{PC: pc, File: file, Line: line, Fn: fn} + inst, err := asmDecode(mem, pc) + if err == nil { + atpc := currentGoroutine && (curpc == pc) + destloc := thread.resolveCallArg(inst, atpc, regs) + r = append(r, AsmInstruction{Loc: loc, DestLoc: destloc, Bytes: mem[:inst.Len], Breakpoint: atbp, AtPC: atpc, Inst: inst}) + + pc += uint64(inst.Size()) + mem = mem[inst.Size():] + } else { + r = append(r, AsmInstruction{Loc: loc, Bytes: mem[:1], Breakpoint: atbp, Inst: nil}) + pc++ + mem = mem[1:] + } + } + return r, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/disasm_amd64.go b/vendor/github.com/derekparker/delve/pkg/proc/disasm_amd64.go new file mode 100644 index 0000000..ebe085b --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/disasm_amd64.go @@ -0,0 +1,184 @@ +package proc + +import ( + "debug/gosym" + "encoding/binary" + + "rsc.io/x86/x86asm" +) + +var maxInstructionLength uint64 = 15 + +type ArchInst x86asm.Inst + +func asmDecode(mem []byte, pc uint64) (*ArchInst, error) { + inst, err := x86asm.Decode(mem, 64) + if err != nil { + return nil, err + } + patchPCRel(pc, &inst) + r := ArchInst(inst) + return &r, nil +} + +func (inst *ArchInst) Size() int { + return inst.Len +} + +// converts PC relative arguments to absolute addresses +func patchPCRel(pc uint64, inst *x86asm.Inst) { + for i := range inst.Args { + rel, isrel := inst.Args[i].(x86asm.Rel) + if isrel { + inst.Args[i] = x86asm.Imm(int64(pc) + int64(rel) + int64(inst.Len)) + } + } + return +} + +func (inst *AsmInstruction) Text(flavour AssemblyFlavour) string { + if inst.Inst == nil { + return "?" + } + + var text string + + switch flavour { + case GNUFlavour: + text = x86asm.GNUSyntax(x86asm.Inst(*inst.Inst)) + case IntelFlavour: + fallthrough + default: + text = x86asm.IntelSyntax(x86asm.Inst(*inst.Inst)) + } + + if inst.IsCall() && inst.DestLoc != nil && inst.DestLoc.Fn != nil { + text += " " + inst.DestLoc.Fn.Name + } + + return text +} + +func (inst *AsmInstruction) IsCall() bool { + return inst.Inst.Op == x86asm.CALL || inst.Inst.Op == x86asm.LCALL +} + +func (thread *Thread) resolveCallArg(inst *ArchInst, currentGoroutine bool, regs Registers) *Location { + if inst.Op != x86asm.CALL && inst.Op != x86asm.LCALL { + return nil + } + + var pc uint64 + var err error + + switch arg := inst.Args[0].(type) { + case x86asm.Imm: + pc = uint64(arg) + case x86asm.Reg: + if !currentGoroutine || regs == nil { + return nil + } + pc, err = regs.Get(int(arg)) + if err != nil { + return nil + } + case x86asm.Mem: + if !currentGoroutine || regs == nil { + return nil + } + if arg.Segment != 0 { + return nil + } + regs, err := thread.Registers(false) + if err != nil { + return nil + } + base, err1 := regs.Get(int(arg.Base)) + index, err2 := regs.Get(int(arg.Index)) + if err1 != nil || err2 != nil { + return nil + } + addr := uintptr(int64(base) + int64(index*uint64(arg.Scale)) + arg.Disp) + //TODO: should this always be 64 bits instead of inst.MemBytes? + pcbytes, err := thread.readMemory(addr, inst.MemBytes) + if err != nil { + return nil + } + pc = binary.LittleEndian.Uint64(pcbytes) + default: + return nil + } + + file, line, fn := thread.dbp.PCToLine(pc) + if fn == nil { + return nil + } + return &Location{PC: pc, File: file, Line: line, Fn: fn} +} + +type instrseq []x86asm.Op + +// Possible stacksplit prologues are inserted by stacksplit in +// $GOROOT/src/cmd/internal/obj/x86/obj6.go. +// The stacksplit prologue will always begin with loading curg in CX, this +// instruction is added by load_g_cx in the same file and is either 1 or 2 +// MOVs. +var prologues []instrseq + +func init() { + var tinyStacksplit = instrseq{x86asm.CMP, x86asm.JBE} + var smallStacksplit = instrseq{x86asm.LEA, x86asm.CMP, x86asm.JBE} + var bigStacksplit = instrseq{x86asm.MOV, x86asm.CMP, x86asm.JE, x86asm.LEA, x86asm.SUB, x86asm.CMP, x86asm.JBE} + var unixGetG = instrseq{x86asm.MOV} + var windowsGetG = instrseq{x86asm.MOV, x86asm.MOV} + + prologues = make([]instrseq, 0, 2*3) + for _, getG := range []instrseq{unixGetG, windowsGetG} { + for _, stacksplit := range []instrseq{tinyStacksplit, smallStacksplit, bigStacksplit} { + prologue := make(instrseq, 0, len(getG)+len(stacksplit)) + prologue = append(prologue, getG...) + prologue = append(prologue, stacksplit...) + prologues = append(prologues, prologue) + } + } +} + +// FirstPCAfterPrologue returns the address of the first instruction after the prologue for function fn +// If sameline is set FirstPCAfterPrologue will always return an address associated with the same line as fn.Entry +func (dbp *Process) FirstPCAfterPrologue(fn *gosym.Func, sameline bool) (uint64, error) { + text, err := dbp.CurrentThread().Disassemble(fn.Entry, fn.End, false) + if err != nil { + return fn.Entry, err + } + + if len(text) <= 0 { + return fn.Entry, nil + } + + for _, prologue := range prologues { + if len(prologue) >= len(text) { + continue + } + if checkPrologue(text, prologue) { + r := &text[len(prologue)] + if sameline { + if r.Loc.Line != text[0].Loc.Line { + return fn.Entry, nil + } + } + return r.Loc.PC, nil + } + } + + return fn.Entry, nil +} + +func checkPrologue(s []AsmInstruction, prologuePattern instrseq) bool { + line := s[0].Loc.Line + for i, op := range prologuePattern { + if s[i].Inst.Op != op || s[i].Loc.Line != line { + return false + } + } + return true +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/doc.go b/vendor/github.com/derekparker/delve/pkg/proc/doc.go new file mode 100644 index 0000000..6079887 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/doc.go @@ -0,0 +1,9 @@ +// Package proc is a low-level package that provides methods to manipulate +// the process we are debugging. +// +// proc implements all core functionality including: +// * creating / attaching to a process +// * process manipulation (step, next, continue, halt) +// * methods to explore the memory of the process +// +package proc diff --git a/vendor/github.com/derekparker/delve/pkg/proc/eval.go b/vendor/github.com/derekparker/delve/pkg/proc/eval.go new file mode 100644 index 0000000..0b50cb8 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/eval.go @@ -0,0 +1,1131 @@ +package proc + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "go/ast" + "go/constant" + "go/parser" + "go/printer" + "go/token" + "reflect" + + "github.com/derekparker/delve/pkg/dwarf/reader" + "golang.org/x/debug/dwarf" +) + +var OperationOnSpecialFloatError = errors.New("operations on non-finite floats not implemented") + +// EvalExpression returns the value of the given expression. +func (scope *EvalScope) EvalExpression(expr string, cfg LoadConfig) (*Variable, error) { + t, err := parser.ParseExpr(expr) + if err != nil { + return nil, err + } + + ev, err := scope.evalAST(t) + if err != nil { + return nil, err + } + ev.loadValue(cfg) + if ev.Name == "" { + ev.Name = expr + } + return ev, nil +} + +func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) { + switch node := t.(type) { + case *ast.CallExpr: + if len(node.Args) == 1 { + v, err := scope.evalTypeCast(node) + if err == nil { + return v, nil + } + _, isident := node.Fun.(*ast.Ident) + // we don't support function calls at the moment except for a few + // builtin functions so just return the type error here if the function + // isn't an identifier. + // More sophisticated logic will be required when function calls + // are implemented. + if err != reader.TypeNotFoundErr || !isident { + return v, err + } + } + return scope.evalBuiltinCall(node) + + case *ast.Ident: + return scope.evalIdent(node) + + case *ast.ParenExpr: + // otherwise just eval recursively + return scope.evalAST(node.X) + + case *ast.SelectorExpr: // . + // try to interpret the selector as a package variable + if maybePkg, ok := node.X.(*ast.Ident); ok { + if maybePkg.Name == "runtime" && node.Sel.Name == "curg" { + return scope.Thread.getGVariable() + } else if v, err := scope.packageVarAddr(maybePkg.Name + "." + node.Sel.Name); err == nil { + return v, nil + } + } + // if it's not a package variable then it must be a struct member access + return scope.evalStructSelector(node) + + case *ast.TypeAssertExpr: // .() + return scope.evalTypeAssert(node) + + case *ast.IndexExpr: + return scope.evalIndex(node) + + case *ast.SliceExpr: + if node.Slice3 { + return nil, fmt.Errorf("3-index slice expressions not supported") + } + return scope.evalReslice(node) + + case *ast.StarExpr: + // pointer dereferencing * + return scope.evalPointerDeref(node) + + case *ast.UnaryExpr: + // The unary operators we support are +, - and & (note that unary * is parsed as ast.StarExpr) + switch node.Op { + case token.AND: + return scope.evalAddrOf(node) + + default: + return scope.evalUnary(node) + } + + case *ast.BinaryExpr: + return scope.evalBinary(node) + + case *ast.BasicLit: + return newConstant(constant.MakeFromLiteral(node.Value, node.Kind, 0), scope.Thread), nil + + default: + return nil, fmt.Errorf("expression %T not implemented", t) + + } +} + +func exprToString(t ast.Expr) string { + var buf bytes.Buffer + printer.Fprint(&buf, token.NewFileSet(), t) + return buf.String() +} + +// Eval type cast expressions +func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) { + argv, err := scope.evalAST(node.Args[0]) + if err != nil { + return nil, err + } + argv.loadValue(loadSingleValue) + if argv.Unreadable != nil { + return nil, argv.Unreadable + } + + fnnode := node.Fun + + // remove all enclosing parenthesis from the type name + for { + p, ok := fnnode.(*ast.ParenExpr) + if !ok { + break + } + fnnode = p.X + } + + styp, err := scope.Thread.dbp.findTypeExpr(fnnode) + if err != nil { + return nil, err + } + typ := resolveTypedef(styp) + + converr := fmt.Errorf("can not convert %q to %s", exprToString(node.Args[0]), typ.String()) + + v := newVariable("", 0, styp, scope.Thread.dbp, scope.Thread) + v.loaded = true + + switch ttyp := typ.(type) { + case *dwarf.PtrType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // ok + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + // ok + default: + return nil, converr + } + + n, _ := constant.Int64Val(argv.Value) + + v.Children = []Variable{*(scope.newVariable("", uintptr(n), ttyp.Type))} + return v, nil + + case *dwarf.UintType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, _ := constant.Int64Val(argv.Value) + v.Value = constant.MakeUint64(convertInt(uint64(n), false, ttyp.Size())) + return v, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n, _ := constant.Uint64Val(argv.Value) + v.Value = constant.MakeUint64(convertInt(n, false, ttyp.Size())) + return v, nil + case reflect.Float32, reflect.Float64: + x, _ := constant.Float64Val(argv.Value) + v.Value = constant.MakeUint64(uint64(x)) + return v, nil + } + case *dwarf.IntType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, _ := constant.Int64Val(argv.Value) + v.Value = constant.MakeInt64(int64(convertInt(uint64(n), true, ttyp.Size()))) + return v, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n, _ := constant.Uint64Val(argv.Value) + v.Value = constant.MakeInt64(int64(convertInt(n, true, ttyp.Size()))) + return v, nil + case reflect.Float32, reflect.Float64: + x, _ := constant.Float64Val(argv.Value) + v.Value = constant.MakeInt64(int64(x)) + return v, nil + } + case *dwarf.FloatType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + fallthrough + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + fallthrough + case reflect.Float32, reflect.Float64: + v.Value = argv.Value + return v, nil + } + case *dwarf.ComplexType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + fallthrough + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + fallthrough + case reflect.Float32, reflect.Float64: + v.Value = argv.Value + return v, nil + } + } + + return nil, converr +} + +func convertInt(n uint64, signed bool, size int64) uint64 { + buf := make([]byte, 64/8) + binary.BigEndian.PutUint64(buf, n) + m := 64/8 - int(size) + s := byte(0) + if signed && (buf[m]&0x80 > 0) { + s = 0xff + } + for i := 0; i < m; i++ { + buf[i] = s + } + return uint64(binary.BigEndian.Uint64(buf)) +} + +func (scope *EvalScope) evalBuiltinCall(node *ast.CallExpr) (*Variable, error) { + fnnode, ok := node.Fun.(*ast.Ident) + if !ok { + return nil, fmt.Errorf("function calls are not supported") + } + + args := make([]*Variable, len(node.Args)) + + for i := range node.Args { + v, err := scope.evalAST(node.Args[i]) + if err != nil { + return nil, err + } + args[i] = v + } + + switch fnnode.Name { + case "cap": + return capBuiltin(args, node.Args) + case "len": + return lenBuiltin(args, node.Args) + case "complex": + return complexBuiltin(args, node.Args) + case "imag": + return imagBuiltin(args, node.Args) + case "real": + return realBuiltin(args, node.Args) + } + + return nil, fmt.Errorf("function calls are not supported") +} + +func capBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { + if len(args) != 1 { + return nil, fmt.Errorf("wrong number of arguments to cap: %d", len(args)) + } + + arg := args[0] + invalidArgErr := fmt.Errorf("invalid argument %s (type %s) for cap", exprToString(nodeargs[0]), arg.TypeString()) + + switch arg.Kind { + case reflect.Ptr: + arg = arg.maybeDereference() + if arg.Kind != reflect.Array { + return nil, invalidArgErr + } + fallthrough + case reflect.Array: + return newConstant(constant.MakeInt64(arg.Len), arg.mem), nil + case reflect.Slice: + return newConstant(constant.MakeInt64(arg.Cap), arg.mem), nil + case reflect.Chan: + arg.loadValue(loadFullValue) + if arg.Unreadable != nil { + return nil, arg.Unreadable + } + if arg.Base == 0 { + return newConstant(constant.MakeInt64(0), arg.mem), nil + } + return newConstant(arg.Children[1].Value, arg.mem), nil + default: + return nil, invalidArgErr + } +} + +func lenBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { + if len(args) != 1 { + return nil, fmt.Errorf("wrong number of arguments to len: %d", len(args)) + } + arg := args[0] + invalidArgErr := fmt.Errorf("invalid argument %s (type %s) for len", exprToString(nodeargs[0]), arg.TypeString()) + + switch arg.Kind { + case reflect.Ptr: + arg = arg.maybeDereference() + if arg.Kind != reflect.Array { + return nil, invalidArgErr + } + fallthrough + case reflect.Array, reflect.Slice, reflect.String: + if arg.Unreadable != nil { + return nil, arg.Unreadable + } + return newConstant(constant.MakeInt64(arg.Len), arg.mem), nil + case reflect.Chan: + arg.loadValue(loadFullValue) + if arg.Unreadable != nil { + return nil, arg.Unreadable + } + if arg.Base == 0 { + return newConstant(constant.MakeInt64(0), arg.mem), nil + } + return newConstant(arg.Children[0].Value, arg.mem), nil + case reflect.Map: + it := arg.mapIterator() + if arg.Unreadable != nil { + return nil, arg.Unreadable + } + if it == nil { + return newConstant(constant.MakeInt64(0), arg.mem), nil + } + return newConstant(constant.MakeInt64(arg.Len), arg.mem), nil + default: + return nil, invalidArgErr + } +} + +func complexBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { + if len(args) != 2 { + return nil, fmt.Errorf("wrong number of arguments to complex: %d", len(args)) + } + + realev := args[0] + imagev := args[1] + + realev.loadValue(loadSingleValue) + imagev.loadValue(loadSingleValue) + + if realev.Unreadable != nil { + return nil, realev.Unreadable + } + + if imagev.Unreadable != nil { + return nil, imagev.Unreadable + } + + if realev.Value == nil || ((realev.Value.Kind() != constant.Int) && (realev.Value.Kind() != constant.Float)) { + return nil, fmt.Errorf("invalid argument 1 %s (type %s) to complex", exprToString(nodeargs[0]), realev.TypeString()) + } + + if imagev.Value == nil || ((imagev.Value.Kind() != constant.Int) && (imagev.Value.Kind() != constant.Float)) { + return nil, fmt.Errorf("invalid argument 2 %s (type %s) to complex", exprToString(nodeargs[1]), imagev.TypeString()) + } + + sz := int64(0) + if realev.RealType != nil { + sz = realev.RealType.(*dwarf.FloatType).Size() + } + if imagev.RealType != nil { + isz := imagev.RealType.(*dwarf.FloatType).Size() + if isz > sz { + sz = isz + } + } + + if sz == 0 { + sz = 128 + } + + typ := &dwarf.ComplexType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: int64(sz / 8), Name: fmt.Sprintf("complex%d", sz)}, BitSize: sz, BitOffset: 0}} + + r := realev.newVariable("", 0, typ) + r.Value = constant.BinaryOp(realev.Value, token.ADD, constant.MakeImag(imagev.Value)) + return r, nil +} + +func imagBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { + if len(args) != 1 { + return nil, fmt.Errorf("wrong number of arguments to imag: %d", len(args)) + } + + arg := args[0] + arg.loadValue(loadSingleValue) + + if arg.Unreadable != nil { + return nil, arg.Unreadable + } + + if arg.Kind != reflect.Complex64 && arg.Kind != reflect.Complex128 { + return nil, fmt.Errorf("invalid argument %s (type %s) to imag", exprToString(nodeargs[0]), arg.TypeString()) + } + + return newConstant(constant.Imag(arg.Value), arg.mem), nil +} + +func realBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { + if len(args) != 1 { + return nil, fmt.Errorf("wrong number of arguments to real: %d", len(args)) + } + + arg := args[0] + arg.loadValue(loadSingleValue) + + if arg.Unreadable != nil { + return nil, arg.Unreadable + } + + if arg.Value == nil || ((arg.Value.Kind() != constant.Int) && (arg.Value.Kind() != constant.Float) && (arg.Value.Kind() != constant.Complex)) { + return nil, fmt.Errorf("invalid argument %s (type %s) to real", exprToString(nodeargs[0]), arg.TypeString()) + } + + return newConstant(constant.Real(arg.Value), arg.mem), nil +} + +// Evaluates identifier expressions +func (scope *EvalScope) evalIdent(node *ast.Ident) (*Variable, error) { + switch node.Name { + case "true", "false": + return newConstant(constant.MakeBool(node.Name == "true"), scope.Thread), nil + case "nil": + return nilVariable, nil + } + + // try to interpret this as a local variable + v, err := scope.extractVarInfo(node.Name) + if err == nil { + return v, nil + } + origErr := err + // workaround: sometimes go inserts an entry for '&varname' instead of varname + v, err = scope.extractVarInfo("&" + node.Name) + if err == nil { + v = v.maybeDereference() + v.Name = node.Name + return v, nil + } + // if it's not a local variable then it could be a package variable w/o explicit package name + _, _, fn := scope.Thread.dbp.PCToLine(scope.PC) + if fn != nil { + if v, err = scope.packageVarAddr(fn.PackageName() + "." + node.Name); err == nil { + v.Name = node.Name + return v, nil + } + } + return nil, origErr +} + +// Evaluates expressions . where subexpr is not a package name +func (scope *EvalScope) evalStructSelector(node *ast.SelectorExpr) (*Variable, error) { + xv, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + return xv.structMember(node.Sel.Name) +} + +// Evaluates expressions .() +func (scope *EvalScope) evalTypeAssert(node *ast.TypeAssertExpr) (*Variable, error) { + xv, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + if xv.Kind != reflect.Interface { + return nil, fmt.Errorf("expression \"%s\" not an interface", exprToString(node.X)) + } + xv.loadInterface(0, false, loadFullValue) + if xv.Unreadable != nil { + return nil, xv.Unreadable + } + if xv.Children[0].Unreadable != nil { + return nil, xv.Children[0].Unreadable + } + if xv.Children[0].Addr == 0 { + return nil, fmt.Errorf("interface conversion: %s is nil, not %s", xv.DwarfType.String(), exprToString(node.Type)) + } + typ, err := scope.Thread.dbp.findTypeExpr(node.Type) + if err != nil { + return nil, err + } + if xv.Children[0].DwarfType.Common().Name != typ.Common().Name { + return nil, fmt.Errorf("interface conversion: %s is %s, not %s", xv.DwarfType.Common().Name, xv.Children[0].TypeString(), typ.Common().Name) + } + return &xv.Children[0], nil +} + +// Evaluates expressions [] (subscript access to arrays, slices and maps) +func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) { + xev, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + if xev.Unreadable != nil { + return nil, xev.Unreadable + } + + idxev, err := scope.evalAST(node.Index) + if err != nil { + return nil, err + } + + switch xev.Kind { + case reflect.Slice, reflect.Array, reflect.String: + if xev.Base == 0 { + return nil, fmt.Errorf("can not index \"%s\"", exprToString(node.X)) + } + n, err := idxev.asInt() + if err != nil { + return nil, err + } + return xev.sliceAccess(int(n)) + + case reflect.Map: + idxev.loadValue(loadFullValue) + if idxev.Unreadable != nil { + return nil, idxev.Unreadable + } + return xev.mapAccess(idxev) + default: + return nil, fmt.Errorf("expression \"%s\" (%s) does not support indexing", exprToString(node.X), xev.TypeString()) + + } +} + +// Evaluates expressions [:] +// HACK: slicing a map expression with [0:0] will return the whole map +func (scope *EvalScope) evalReslice(node *ast.SliceExpr) (*Variable, error) { + xev, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + if xev.Unreadable != nil { + return nil, xev.Unreadable + } + + var low, high int64 + + if node.Low != nil { + lowv, err := scope.evalAST(node.Low) + if err != nil { + return nil, err + } + low, err = lowv.asInt() + if err != nil { + return nil, fmt.Errorf("can not convert \"%s\" to int: %v", exprToString(node.Low), err) + } + } + + if node.High == nil { + high = xev.Len + } else { + highv, err := scope.evalAST(node.High) + if err != nil { + return nil, err + } + high, err = highv.asInt() + if err != nil { + return nil, fmt.Errorf("can not convert \"%s\" to int: %v", exprToString(node.High), err) + } + } + + switch xev.Kind { + case reflect.Slice, reflect.Array, reflect.String: + if xev.Base == 0 { + return nil, fmt.Errorf("can not slice \"%s\"", exprToString(node.X)) + } + return xev.reslice(low, high) + case reflect.Map: + if node.High != nil { + return nil, fmt.Errorf("second slice argument must be empty for maps") + } + xev.mapSkip += int(low) + xev.loadValue(loadFullValue) + if xev.Unreadable != nil { + return nil, xev.Unreadable + } + return xev, nil + default: + return nil, fmt.Errorf("can not slice \"%s\" (type %s)", exprToString(node.X), xev.TypeString()) + } +} + +// Evaluates a pointer dereference expression: * +func (scope *EvalScope) evalPointerDeref(node *ast.StarExpr) (*Variable, error) { + xev, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + + if xev.Kind != reflect.Ptr { + return nil, fmt.Errorf("expression \"%s\" (%s) can not be dereferenced", exprToString(node.X), xev.TypeString()) + } + + if xev == nilVariable { + return nil, fmt.Errorf("nil can not be dereferenced") + } + + if len(xev.Children) == 1 { + // this branch is here to support pointers constructed with typecasts from ints + return &(xev.Children[0]), nil + } + rv := xev.maybeDereference() + if rv.Addr == 0 { + return nil, fmt.Errorf("nil pointer dereference") + } + return rv, nil +} + +// Evaluates expressions & +func (scope *EvalScope) evalAddrOf(node *ast.UnaryExpr) (*Variable, error) { + xev, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + if xev.Addr == 0 || xev.DwarfType == nil { + return nil, fmt.Errorf("can not take address of \"%s\"", exprToString(node.X)) + } + + xev.OnlyAddr = true + + typename := "*" + xev.DwarfType.Common().Name + rv := scope.newVariable("", 0, &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: int64(scope.Thread.dbp.arch.PtrSize()), Name: typename}, Type: xev.DwarfType}) + rv.Children = []Variable{*xev} + rv.loaded = true + + return rv, nil +} + +func constantUnaryOp(op token.Token, y constant.Value) (r constant.Value, err error) { + defer func() { + if ierr := recover(); ierr != nil { + err = fmt.Errorf("%v", ierr) + } + }() + r = constant.UnaryOp(op, y, 0) + return +} + +func constantBinaryOp(op token.Token, x, y constant.Value) (r constant.Value, err error) { + defer func() { + if ierr := recover(); ierr != nil { + err = fmt.Errorf("%v", ierr) + } + }() + switch op { + case token.SHL, token.SHR: + n, _ := constant.Uint64Val(y) + r = constant.Shift(x, op, uint(n)) + default: + r = constant.BinaryOp(x, op, y) + } + return +} + +func constantCompare(op token.Token, x, y constant.Value) (r bool, err error) { + defer func() { + if ierr := recover(); ierr != nil { + err = fmt.Errorf("%v", ierr) + } + }() + r = constant.Compare(x, op, y) + return +} + +// Evaluates expressions: - and + +func (scope *EvalScope) evalUnary(node *ast.UnaryExpr) (*Variable, error) { + xv, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + + xv.loadValue(loadSingleValue) + if xv.Unreadable != nil { + return nil, xv.Unreadable + } + if xv.FloatSpecial != 0 { + return nil, OperationOnSpecialFloatError + } + if xv.Value == nil { + return nil, fmt.Errorf("operator %s can not be applied to \"%s\"", node.Op.String(), exprToString(node.X)) + } + rc, err := constantUnaryOp(node.Op, xv.Value) + if err != nil { + return nil, err + } + if xv.DwarfType != nil { + r := xv.newVariable("", 0, xv.DwarfType) + r.Value = rc + return r, nil + } + return newConstant(rc, xv.mem), nil +} + +func negotiateType(op token.Token, xv, yv *Variable) (dwarf.Type, error) { + if xv == nilVariable { + return nil, negotiateTypeNil(op, yv) + } + + if yv == nilVariable { + return nil, negotiateTypeNil(op, xv) + } + + if op == token.SHR || op == token.SHL { + if xv.Value == nil || xv.Value.Kind() != constant.Int { + return nil, fmt.Errorf("shift of type %s", xv.Kind) + } + + switch yv.Kind { + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + // ok + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if yv.DwarfType != nil || constant.Sign(yv.Value) < 0 { + return nil, fmt.Errorf("shift count type %s, must be unsigned integer", yv.Kind.String()) + } + default: + return nil, fmt.Errorf("shift count type %s, must be unsigned integer", yv.Kind.String()) + } + + return xv.DwarfType, nil + } + + if xv.DwarfType == nil && yv.DwarfType == nil { + return nil, nil + } + + if xv.DwarfType != nil && yv.DwarfType != nil { + if xv.DwarfType.String() != yv.DwarfType.String() { + return nil, fmt.Errorf("mismatched types \"%s\" and \"%s\"", xv.DwarfType.String(), yv.DwarfType.String()) + } + return xv.DwarfType, nil + } else if xv.DwarfType != nil && yv.DwarfType == nil { + if err := yv.isType(xv.DwarfType, xv.Kind); err != nil { + return nil, err + } + return xv.DwarfType, nil + } else if xv.DwarfType == nil && yv.DwarfType != nil { + if err := xv.isType(yv.DwarfType, yv.Kind); err != nil { + return nil, err + } + return yv.DwarfType, nil + } + + panic("unreachable") +} + +func negotiateTypeNil(op token.Token, v *Variable) error { + if op != token.EQL && op != token.NEQ { + return fmt.Errorf("operator %s can not be applied to \"nil\"", op.String()) + } + switch v.Kind { + case reflect.Ptr, reflect.UnsafePointer, reflect.Chan, reflect.Map, reflect.Interface, reflect.Slice, reflect.Func: + return nil + default: + return fmt.Errorf("can not compare %s to nil", v.Kind.String()) + } +} + +func (scope *EvalScope) evalBinary(node *ast.BinaryExpr) (*Variable, error) { + switch node.Op { + case token.INC, token.DEC, token.ARROW: + return nil, fmt.Errorf("operator %s not supported", node.Op.String()) + } + + xv, err := scope.evalAST(node.X) + if err != nil { + return nil, err + } + + yv, err := scope.evalAST(node.Y) + if err != nil { + return nil, err + } + + xv.loadValue(loadFullValue) + yv.loadValue(loadFullValue) + + if xv.Unreadable != nil { + return nil, xv.Unreadable + } + + if yv.Unreadable != nil { + return nil, yv.Unreadable + } + + if xv.FloatSpecial != 0 || yv.FloatSpecial != 0 { + return nil, OperationOnSpecialFloatError + } + + typ, err := negotiateType(node.Op, xv, yv) + if err != nil { + return nil, err + } + + op := node.Op + if typ != nil && (op == token.QUO) { + _, isint := typ.(*dwarf.IntType) + _, isuint := typ.(*dwarf.UintType) + if isint || isuint { + // forces integer division if the result type is integer + op = token.QUO_ASSIGN + } + } + + switch op { + case token.EQL, token.LSS, token.GTR, token.NEQ, token.LEQ, token.GEQ: + v, err := compareOp(op, xv, yv) + if err != nil { + return nil, err + } + return newConstant(constant.MakeBool(v), xv.mem), nil + + default: + if xv.Value == nil { + return nil, fmt.Errorf("operator %s can not be applied to \"%s\"", node.Op.String(), exprToString(node.X)) + } + + if yv.Value == nil { + return nil, fmt.Errorf("operator %s can not be applied to \"%s\"", node.Op.String(), exprToString(node.Y)) + } + + rc, err := constantBinaryOp(op, xv.Value, yv.Value) + if err != nil { + return nil, err + } + + if typ == nil { + return newConstant(rc, xv.mem), nil + } + + r := xv.newVariable("", 0, typ) + r.Value = rc + return r, nil + } +} + +// Comapres xv to yv using operator op +// Both xv and yv must be loaded and have a compatible type (as determined by negotiateType) +func compareOp(op token.Token, xv *Variable, yv *Variable) (bool, error) { + switch xv.Kind { + case reflect.Bool: + fallthrough + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + fallthrough + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + fallthrough + case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + return constantCompare(op, xv.Value, yv.Value) + case reflect.String: + if int64(len(constant.StringVal(xv.Value))) != xv.Len || int64(len(constant.StringVal(yv.Value))) != yv.Len { + return false, fmt.Errorf("string too long for comparison") + } + return constantCompare(op, xv.Value, yv.Value) + } + + if op != token.EQL && op != token.NEQ { + return false, fmt.Errorf("operator %s not defined on %s", op.String(), xv.Kind.String()) + } + + var eql bool + var err error + + if xv == nilVariable { + switch op { + case token.EQL: + return yv.isNil(), nil + case token.NEQ: + return !yv.isNil(), nil + } + } + + if yv == nilVariable { + switch op { + case token.EQL: + return xv.isNil(), nil + case token.NEQ: + return !xv.isNil(), nil + } + } + + switch xv.Kind { + case reflect.Ptr: + eql = xv.Children[0].Addr == yv.Children[0].Addr + case reflect.Array: + if int64(len(xv.Children)) != xv.Len || int64(len(yv.Children)) != yv.Len { + return false, fmt.Errorf("array too long for comparison") + } + eql, err = equalChildren(xv, yv, true) + case reflect.Struct: + if len(xv.Children) != len(yv.Children) { + return false, nil + } + if int64(len(xv.Children)) != xv.Len || int64(len(yv.Children)) != yv.Len { + return false, fmt.Errorf("sturcture too deep for comparison") + } + eql, err = equalChildren(xv, yv, false) + case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: + return false, fmt.Errorf("can not compare %s variables", xv.Kind.String()) + case reflect.Interface: + if xv.Children[0].RealType.String() != yv.Children[0].RealType.String() { + eql = false + } else { + eql, err = compareOp(token.EQL, &xv.Children[0], &yv.Children[0]) + } + default: + return false, fmt.Errorf("unimplemented comparison of %s variables", xv.Kind.String()) + } + + if op == token.NEQ { + return !eql, err + } + return eql, err +} + +func (v *Variable) isNil() bool { + switch v.Kind { + case reflect.Ptr: + return v.Children[0].Addr == 0 + case reflect.Interface: + return false + case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: + return v.Base == 0 + } + return false +} + +func equalChildren(xv, yv *Variable, shortcircuit bool) (bool, error) { + r := true + for i := range xv.Children { + eql, err := compareOp(token.EQL, &xv.Children[i], &yv.Children[i]) + if err != nil { + return false, err + } + r = r && eql + if !r && shortcircuit { + return false, nil + } + } + return r, nil +} + +func (v *Variable) asInt() (int64, error) { + if v.DwarfType == nil { + if v.Value.Kind() != constant.Int { + return 0, fmt.Errorf("can not convert constant %s to int", v.Value) + } + } else { + v.loadValue(loadSingleValue) + if v.Unreadable != nil { + return 0, v.Unreadable + } + if _, ok := v.DwarfType.(*dwarf.IntType); !ok { + return 0, fmt.Errorf("can not convert value of type %s to int", v.DwarfType.String()) + } + } + n, _ := constant.Int64Val(v.Value) + return n, nil +} + +func (v *Variable) asUint() (uint64, error) { + if v.DwarfType == nil { + if v.Value.Kind() != constant.Int { + return 0, fmt.Errorf("can not convert constant %s to uint", v.Value) + } + } else { + v.loadValue(loadSingleValue) + if v.Unreadable != nil { + return 0, v.Unreadable + } + if _, ok := v.DwarfType.(*dwarf.UintType); !ok { + return 0, fmt.Errorf("can not convert value of type %s to uint", v.DwarfType.String()) + } + } + n, _ := constant.Uint64Val(v.Value) + return n, nil +} + +func (v *Variable) isType(typ dwarf.Type, kind reflect.Kind) error { + if v.DwarfType != nil { + if typ != nil && typ.String() != v.RealType.String() { + return fmt.Errorf("can not convert value of type %s to %s", v.DwarfType.String(), typ.String()) + } + return nil + } + + if typ == nil { + return nil + } + + if v == nilVariable { + switch kind { + case reflect.Slice, reflect.Map, reflect.Func, reflect.Ptr, reflect.Chan, reflect.Interface: + return nil + default: + return fmt.Errorf("mismatched types nil and %s", typ.String()) + } + } + + converr := fmt.Errorf("can not convert %s constant to %s", v.Value, typ.String()) + + if v.Value == nil { + return converr + } + + switch typ.(type) { + case *dwarf.IntType: + if v.Value.Kind() != constant.Int { + return converr + } + case *dwarf.UintType: + if v.Value.Kind() != constant.Int { + return converr + } + case *dwarf.FloatType: + if (v.Value.Kind() != constant.Int) && (v.Value.Kind() != constant.Float) { + return converr + } + case *dwarf.BoolType: + if v.Value.Kind() != constant.Bool { + return converr + } + case *dwarf.StringType: + if v.Value.Kind() != constant.String { + return converr + } + case *dwarf.ComplexType: + if v.Value.Kind() != constant.Complex && v.Value.Kind() != constant.Float && v.Value.Kind() != constant.Int { + return converr + } + default: + return converr + } + + return nil +} + +func (v *Variable) sliceAccess(idx int) (*Variable, error) { + if idx < 0 || int64(idx) >= v.Len { + return nil, fmt.Errorf("index out of bounds") + } + return v.newVariable("", v.Base+uintptr(int64(idx)*v.stride), v.fieldType), nil +} + +func (v *Variable) mapAccess(idx *Variable) (*Variable, error) { + it := v.mapIterator() + if it == nil { + return nil, fmt.Errorf("can not access unreadable map: %v", v.Unreadable) + } + + first := true + for it.next() { + key := it.key() + key.loadValue(loadFullValue) + if key.Unreadable != nil { + return nil, fmt.Errorf("can not access unreadable map: %v", key.Unreadable) + } + if first { + first = false + if err := idx.isType(key.DwarfType, key.Kind); err != nil { + return nil, err + } + } + eql, err := compareOp(token.EQL, key, idx) + if err != nil { + return nil, err + } + if eql { + return it.value(), nil + } + } + if v.Unreadable != nil { + return nil, v.Unreadable + } + // go would return zero for the map value type here, we do not have the ability to create zeroes + return nil, fmt.Errorf("key not found") +} + +func (v *Variable) reslice(low int64, high int64) (*Variable, error) { + if low < 0 || low >= v.Len || high < 0 || high > v.Len { + return nil, fmt.Errorf("index out of bounds") + } + + base := v.Base + uintptr(int64(low)*v.stride) + len := high - low + + if high-low < 0 { + return nil, fmt.Errorf("index out of bounds") + } + + typ := v.DwarfType + if _, isarr := v.DwarfType.(*dwarf.ArrayType); isarr { + typ = &dwarf.SliceType{ + StructType: dwarf.StructType{ + CommonType: dwarf.CommonType{ + ByteSize: 24, + Name: "", + }, + StructName: fmt.Sprintf("[]%s", v.fieldType.Common().Name), + Kind: "struct", + Field: nil, + }, + ElemType: v.fieldType, + } + } + + r := v.newVariable("", 0, typ) + r.Cap = len + r.Len = len + r.Base = base + r.stride = v.stride + r.fieldType = v.fieldType + + return r, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/exc.h b/vendor/github.com/derekparker/delve/pkg/proc/exc.h new file mode 100644 index 0000000..c5c4386 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/exc.h @@ -0,0 +1,283 @@ +#ifndef _exc_user_ +#define _exc_user_ + +/* Module exc */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* BEGIN VOUCHER CODE */ + +#ifndef KERNEL +#if defined(__has_include) +#if __has_include() +#ifndef USING_VOUCHERS +#define USING_VOUCHERS +#endif +#ifndef __VOUCHER_FORWARD_TYPE_DECLS__ +#define __VOUCHER_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif // __VOUCHER_FORWARD_TYPE_DECLS__ +#endif // __has_include() +#endif // __has_include +#endif // !KERNEL + +/* END VOUCHER CODE */ + + +#ifdef AUTOTEST +#ifndef FUNCTION_PTR_T +#define FUNCTION_PTR_T +typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); +typedef struct { + char *name; + function_ptr_t function; +} function_table_entry; +typedef function_table_entry *function_table_t; +#endif /* FUNCTION_PTR_T */ +#endif /* AUTOTEST */ + +#ifndef exc_MSG_COUNT +#define exc_MSG_COUNT 3 +#endif /* exc_MSG_COUNT */ + +#include +#include +#include +#include + +#ifdef __BeforeMigUserHeader +__BeforeMigUserHeader +#endif /* __BeforeMigUserHeader */ + +#include +__BEGIN_DECLS + + +/* Routine exception_raise */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t exception_raise +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t codeCnt +); + +/* Routine exception_raise_state */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t exception_raise_state +( + mach_port_t exception_port, + exception_type_t exception, + const exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine exception_raise_state_identity */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t exception_raise_state_identity +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +__END_DECLS + +/********************** Caution **************************/ +/* The following data types should be used to calculate */ +/* maximum message sizes only. The actual message may be */ +/* smaller, and the position of the arguments within the */ +/* message layout may vary from what is presented here. */ +/* For example, if any of the arguments are variable- */ +/* sized, and less than the maximum is sent, the data */ +/* will be packed tight in the actual message to reduce */ +/* the presence of holes. */ +/********************** Caution **************************/ + +/* typedefs for all requests */ + +#ifndef __Request__exc_subsystem__defined +#define __Request__exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + integer_t code[2]; + } __Request__exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + integer_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } __Request__exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + integer_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } __Request__exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Request__exc_subsystem__defined */ + +/* union of all requests */ + +#ifndef __RequestUnion__exc_subsystem__defined +#define __RequestUnion__exc_subsystem__defined +union __RequestUnion__exc_subsystem { + __Request__exception_raise_t Request_exception_raise; + __Request__exception_raise_state_t Request_exception_raise_state; + __Request__exception_raise_state_identity_t Request_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__exc_subsystem__defined */ +/* typedefs for all replies */ + +#ifndef __Reply__exc_subsystem__defined +#define __Reply__exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply__exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply__exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Reply__exc_subsystem__defined */ + +/* union of all replies */ + +#ifndef __ReplyUnion__exc_subsystem__defined +#define __ReplyUnion__exc_subsystem__defined +union __ReplyUnion__exc_subsystem { + __Reply__exception_raise_t Reply_exception_raise; + __Reply__exception_raise_state_t Reply_exception_raise_state; + __Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__exc_subsystem__defined */ + +#ifndef subsystem_to_name_map_exc +#define subsystem_to_name_map_exc \ + { "exception_raise", 2401 },\ + { "exception_raise_state", 2402 },\ + { "exception_raise_state_identity", 2403 } +#endif + +#ifdef __AfterMigUserHeader +__AfterMigUserHeader +#endif /* __AfterMigUserHeader */ + +#endif /* _exc_user_ */ diff --git a/vendor/github.com/derekparker/delve/pkg/proc/exc_user_darwin.c b/vendor/github.com/derekparker/delve/pkg/proc/exc_user_darwin.c new file mode 100644 index 0000000..bd2e689 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/exc_user_darwin.c @@ -0,0 +1,768 @@ +/* + * IDENTIFICATION: + * stub generated Sun Feb 22 20:54:31 2015 + * with a MiG generated by bootstrap_cmds-91 + * OPTIONS: + */ +#define __MIG_check__Reply__exc_subsystem__ 1 + +#include "exc.h" + + +#ifndef mig_internal +#define mig_internal static __inline__ +#endif /* mig_internal */ + +#ifndef mig_external +#define mig_external +#endif /* mig_external */ + +#if !defined(__MigTypeCheck) && defined(TypeCheck) +#define __MigTypeCheck TypeCheck /* Legacy setting */ +#endif /* !defined(__MigTypeCheck) */ + +#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_) +#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */ +#endif /* !defined(__MigKernelSpecificCode) */ + +#ifndef LimitCheck +#define LimitCheck 0 +#endif /* LimitCheck */ + +#ifndef min +#define min(a,b) ( ((a) < (b))? (a): (b) ) +#endif /* min */ + +#if !defined(_WALIGN_) +#define _WALIGN_(x) (((x) + 3) & ~3) +#endif /* !defined(_WALIGN_) */ + +#if !defined(_WALIGNSZ_) +#define _WALIGNSZ_(x) _WALIGN_(sizeof(x)) +#endif /* !defined(_WALIGNSZ_) */ + +#ifndef UseStaticTemplates +#define UseStaticTemplates 0 +#endif /* UseStaticTemplates */ + +#ifndef __MachMsgErrorWithTimeout +#define __MachMsgErrorWithTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + case MACH_SEND_TIMED_OUT: \ + case MACH_RCV_TIMED_OUT: \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithTimeout */ + +#ifndef __MachMsgErrorWithoutTimeout +#define __MachMsgErrorWithoutTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithoutTimeout */ + +#ifndef __DeclareSendRpc +#define __DeclareSendRpc(_NUM_, _NAME_) +#endif /* __DeclareSendRpc */ + +#ifndef __BeforeSendRpc +#define __BeforeSendRpc(_NUM_, _NAME_) +#endif /* __BeforeSendRpc */ + +#ifndef __AfterSendRpc +#define __AfterSendRpc(_NUM_, _NAME_) +#endif /* __AfterSendRpc */ + +#ifndef __DeclareSendSimple +#define __DeclareSendSimple(_NUM_, _NAME_) +#endif /* __DeclareSendSimple */ + +#ifndef __BeforeSendSimple +#define __BeforeSendSimple(_NUM_, _NAME_) +#endif /* __BeforeSendSimple */ + +#ifndef __AfterSendSimple +#define __AfterSendSimple(_NUM_, _NAME_) +#endif /* __AfterSendSimple */ + +#define msgh_request_port msgh_remote_port +#define msgh_reply_port msgh_local_port + + + +#if ( __MigTypeCheck ) +#if __MIG_check__Reply__exc_subsystem__ +#if !defined(__MIG_check__Reply__exception_raise_t__defined) +#define __MIG_check__Reply__exception_raise_t__defined + +mig_internal kern_return_t __MIG_check__Reply__exception_raise_t(__Reply__exception_raise_t *Out0P) +{ + + typedef __Reply__exception_raise_t __Reply; + if (Out0P->Head.msgh_id != 2501) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + { + return Out0P->RetCode; + } +} +#endif /* !defined(__MIG_check__Reply__exception_raise_t__defined) */ +#endif /* __MIG_check__Reply__exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine exception_raise */ +mig_external kern_return_t exception_raise +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t codeCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + integer_t code[2]; + } Request; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_trailer_t trailer; + } Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + +#ifdef __MIG_check__Reply__exception_raise_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__exception_raise_t__defined */ + + __DeclareSendRpc(2401, "exception_raise") + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t threadTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t taskTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 2; +#if UseStaticTemplates + InP->thread = threadTemplate; + InP->thread.name = thread; +#else /* UseStaticTemplates */ + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + InP->task = taskTemplate; + InP->task.name = task; +#else /* UseStaticTemplates */ + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 4 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size = (mach_msg_size_t)(sizeof(Request) - 8) + ((4 * codeCnt)); + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2401; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2401, "exception_raise") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2401, "exception_raise") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__exception_raise_t__defined) + check_result = __MIG_check__Reply__exception_raise_t((__Reply__exception_raise_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__exception_raise_t__defined) */ + + return KERN_SUCCESS; +} + +#if ( __MigTypeCheck ) +#if __MIG_check__Reply__exc_subsystem__ +#if !defined(__MIG_check__Reply__exception_raise_state_t__defined) +#define __MIG_check__Reply__exception_raise_state_t__defined + +mig_internal kern_return_t __MIG_check__Reply__exception_raise_state_t(__Reply__exception_raise_state_t *Out0P) +{ + + typedef __Reply__exception_raise_state_t __Reply; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + + if (Out0P->Head.msgh_id != 2502) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + msgh_size = Out0P->Head.msgh_size; + + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) && + (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) || + Out0P->RetCode == KERN_SUCCESS))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + if (Out0P->RetCode != KERN_SUCCESS) { + return ((mig_reply_error_t *)Out0P)->RetCode; + } + +#if __MigTypeCheck + if ( Out0P->new_stateCnt > 224 ) + return MIG_TYPE_ERROR; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4)) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Reply__exception_raise_state_t__defined) */ +#endif /* __MIG_check__Reply__exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine exception_raise_state */ +mig_external kern_return_t exception_raise_state +( + mach_port_t exception_port, + exception_type_t exception, + const exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + integer_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } Request; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + mach_msg_trailer_t trailer; + } Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + +#ifdef __MIG_check__Reply__exception_raise_state_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__exception_raise_state_t__defined */ + + __DeclareSendRpc(2402, "exception_raise_state") + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 4 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size_delta = (4 * codeCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 904) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 8); + + InP->flavor = *flavor; + + if (old_stateCnt > 224) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); + + InP->old_stateCnt = old_stateCnt; + + msgh_size += (4 * old_stateCnt); + InP = &Mess.In; + InP->Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2402; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2402, "exception_raise_state") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2402, "exception_raise_state") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__exception_raise_state_t__defined) + check_result = __MIG_check__Reply__exception_raise_state_t((__Reply__exception_raise_state_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__exception_raise_state_t__defined) */ + + *flavor = Out0P->flavor; + + if (Out0P->new_stateCnt > 224) { + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224); + *new_stateCnt = Out0P->new_stateCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); + + *new_stateCnt = Out0P->new_stateCnt; + + return KERN_SUCCESS; +} + +#if ( __MigTypeCheck ) +#if __MIG_check__Reply__exc_subsystem__ +#if !defined(__MIG_check__Reply__exception_raise_state_identity_t__defined) +#define __MIG_check__Reply__exception_raise_state_identity_t__defined + +mig_internal kern_return_t __MIG_check__Reply__exception_raise_state_identity_t(__Reply__exception_raise_state_identity_t *Out0P) +{ + + typedef __Reply__exception_raise_state_identity_t __Reply; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + + if (Out0P->Head.msgh_id != 2503) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + msgh_size = Out0P->Head.msgh_size; + + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) && + (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) || + Out0P->RetCode == KERN_SUCCESS))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + if (Out0P->RetCode != KERN_SUCCESS) { + return ((mig_reply_error_t *)Out0P)->RetCode; + } + +#if __MigTypeCheck + if ( Out0P->new_stateCnt > 224 ) + return MIG_TYPE_ERROR; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4)) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Reply__exception_raise_state_identity_t__defined) */ +#endif /* __MIG_check__Reply__exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine exception_raise_state_identity */ +mig_external kern_return_t exception_raise_state_identity +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + integer_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } Request; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + mach_msg_trailer_t trailer; + } Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + +#ifdef __MIG_check__Reply__exception_raise_state_identity_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__exception_raise_state_identity_t__defined */ + + __DeclareSendRpc(2403, "exception_raise_state_identity") + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t threadTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t taskTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 2; +#if UseStaticTemplates + InP->thread = threadTemplate; + InP->thread.name = thread; +#else /* UseStaticTemplates */ + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + InP->task = taskTemplate; + InP->task.name = task; +#else /* UseStaticTemplates */ + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 4 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size_delta = (4 * codeCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 904) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 8); + + InP->flavor = *flavor; + + if (old_stateCnt > 224) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); + + InP->old_stateCnt = old_stateCnt; + + msgh_size += (4 * old_stateCnt); + InP = &Mess.In; + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2403; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2403, "exception_raise_state_identity") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2403, "exception_raise_state_identity") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__exception_raise_state_identity_t__defined) + check_result = __MIG_check__Reply__exception_raise_state_identity_t((__Reply__exception_raise_state_identity_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__exception_raise_state_identity_t__defined) */ + + *flavor = Out0P->flavor; + + if (Out0P->new_stateCnt > 224) { + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224); + *new_stateCnt = Out0P->new_stateCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); + + *new_stateCnt = Out0P->new_stateCnt; + + return KERN_SUCCESS; +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.c b/vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.c new file mode 100644 index 0000000..67409e3 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.c @@ -0,0 +1,112 @@ +#include "exec_darwin.h" +#include "stdio.h" + +extern char** environ; + +int +close_exec_pipe(int fd[2]) { + if (pipe(fd) < 0) return -1; + if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) return -1; + if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0) return -1; + return 0; +} + +int +fork_exec(char *argv0, char **argv, int size, + char *wd, + task_t *task, + mach_port_t *port_set, + mach_port_t *exception_port, + mach_port_t *notification_port) +{ + // Since we're using mach exceptions instead of signals, + // we need to coordinate between parent and child via pipes + // to ensure that the parent has set the exception ports on + // the child task before it execs. + int fd[2]; + if (close_exec_pipe(fd) < 0) return -1; + + // Create another pipe to signal the parent on exec. + int efd[2]; + if (close_exec_pipe(efd) < 0) return -1; + + kern_return_t kret; + pid_t pid = fork(); + if (pid > 0) { + // In parent. + close(fd[0]); + close(efd[1]); + kret = acquire_mach_task(pid, task, port_set, exception_port, notification_port); + if (kret != KERN_SUCCESS) return -1; + + char msg = 'c'; + write(fd[1], &msg, 1); + close(fd[1]); + + char w; + size_t n = read(efd[0], &w, 1); + close(efd[0]); + if (n != 0) { + // Child died, reap it. + waitpid(pid, NULL, 0); + return -1; + } + return pid; + } + + // Fork succeeded, we are in the child. + int pret, cret; + char sig; + + close(fd[1]); + read(fd[0], &sig, 1); + close(fd[0]); + + // Create a new process group. + if (setpgid(0, 0) < 0) { + perror("setpgid"); + exit(1); + } + + // Set errno to zero before a call to ptrace. + // It is documented that ptrace can return -1 even + // for successful calls. + errno = 0; + pret = ptrace(PT_TRACE_ME, 0, 0, 0); + if (pret != 0 && errno != 0) { + perror("ptrace"); + exit(1); + } + + // Change working directory if wd is not empty. + if (wd && wd[0]) { + errno = 0; + cret = chdir(wd); + if (cret != 0 && errno != 0) { + char *error_msg; + asprintf(&error_msg, "%s '%s'", "chdir", wd); + perror(error_msg); + exit(1); + } + } + + errno = 0; + pret = ptrace(PT_SIGEXC, 0, 0, 0); + if (pret != 0 && errno != 0) { + perror("ptrace"); + exit(1); + } + + sleep(1); + + // Create the child process. + execve(argv0, argv, environ); + + // We should never reach here, but if we did something went wrong. + // Write a message to parent to alert that exec failed. + char msg = 'd'; + write(efd[1], &msg, 1); + close(efd[1]); + + exit(1); +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.h b/vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.h new file mode 100644 index 0000000..995e7e8 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.h @@ -0,0 +1,10 @@ +#include "proc_darwin.h" + +#include +#include +#include +#include +#include + +int +fork_exec(char *, char **, int, char *, task_t*, mach_port_t*, mach_port_t*, mach_port_t*); diff --git a/vendor/github.com/derekparker/delve/pkg/proc/go_version.go b/vendor/github.com/derekparker/delve/pkg/proc/go_version.go new file mode 100644 index 0000000..87d5dec --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/go_version.go @@ -0,0 +1,117 @@ +package proc + +import ( + "strconv" + "strings" +) + +// GoVersion represents the Go version of +// the Go compiler version used to compile +// the target binary. +type GoVersion struct { + Major int + Minor int + Rev int + Beta int + RC int +} + +var ( + GoVer18Beta = GoVersion{1, 8, -1, 0, 0} +) + +func ParseVersionString(ver string) (GoVersion, bool) { + var r GoVersion + var err1, err2, err3 error + + if strings.HasPrefix(ver, "devel") { + return GoVersion{-1, 0, 0, 0, 0}, true + } + + if strings.HasPrefix(ver, "go") { + ver := strings.Split(ver, " ")[0] + v := strings.SplitN(ver[2:], ".", 3) + switch len(v) { + case 2: + r.Major, err1 = strconv.Atoi(v[0]) + vr := strings.SplitN(v[1], "beta", 2) + if len(vr) == 2 { + r.Beta, err3 = strconv.Atoi(vr[1]) + } else { + vr = strings.SplitN(v[1], "rc", 2) + if len(vr) == 2 { + r.RC, err3 = strconv.Atoi(vr[1]) + } else { + r.Minor, err2 = strconv.Atoi(v[1]) + if err2 != nil { + return GoVersion{}, false + } + return r, true + } + } + + r.Minor, err2 = strconv.Atoi(vr[0]) + r.Rev = -1 + + if err1 != nil || err2 != nil || err3 != nil { + return GoVersion{}, false + } + + return r, true + + case 3: + + r.Major, err1 = strconv.Atoi(v[0]) + r.Minor, err2 = strconv.Atoi(v[1]) + r.Rev, err3 = strconv.Atoi(v[2]) + if err1 != nil || err2 != nil || err3 != nil { + return GoVersion{}, false + } + + return r, true + + default: + return GoVersion{}, false + } + } + + return GoVersion{}, false +} + +// AfterOrEqual returns whether one GoVersion is after or +// equal to the other. +func (v *GoVersion) AfterOrEqual(b GoVersion) bool { + if v.Major < b.Major { + return false + } else if v.Major > b.Major { + return true + } + + if v.Minor < b.Minor { + return false + } else if v.Minor > b.Minor { + return true + } + + if v.Rev < b.Rev { + return false + } else if v.Rev > b.Rev { + return true + } + + if v.Beta < b.Beta { + return false + } + + if v.RC < b.RC { + return false + } + + return true +} + +// IsDevel returns whether the GoVersion +// is a development version. +func (v *GoVersion) IsDevel() bool { + return v.Major < 0 +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/mach_exc.defs b/vendor/github.com/derekparker/delve/pkg/proc/mach_exc.defs new file mode 100644 index 0000000..00fae28 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/mach_exc.defs @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * Abstract: + * MiG definitions file for Mach exception interface. + */ + +subsystem +#if KERNEL_USER + KernelUser +#endif + mach_exc 2405; + +#include +#include + +ServerPrefix catch_; + +type mach_exception_data_t = array[*:2] of int64_t; +type exception_type_t = int; + +routine mach_exception_raise( +#if KERNEL_USER + exception_port : mach_port_move_send_t; + thread : mach_port_move_send_t; + task : mach_port_move_send_t; +#else /* KERNEL_USER */ + exception_port : mach_port_t; + thread : mach_port_t; + task : mach_port_t; +#endif /* KERNEL_USER */ + exception : exception_type_t; + code : mach_exception_data_t + ); + +routine mach_exception_raise_state( +#if KERNEL_USER + exception_port : mach_port_move_send_t; +#else /* KERNEL_USER */ + exception_port : mach_port_t; +#endif /* KERNEL_USER */ + exception : exception_type_t; + code : mach_exception_data_t, const; + inout flavor : int; + old_state : thread_state_t, const; + out new_state : thread_state_t); + +routine mach_exception_raise_state_identity( +#if KERNEL_USER + exception_port : mach_port_move_send_t; + thread : mach_port_move_send_t; + task : mach_port_move_send_t; +#else /* KERNEL_USER */ + exception_port : mach_port_t; + thread : mach_port_t; + task : mach_port_t; +#endif /* KERNEL_USER */ + exception : exception_type_t; + code : mach_exception_data_t; + inout flavor : int; + old_state : thread_state_t; + out new_state : thread_state_t); + +/* vim: set ft=c : */ diff --git a/vendor/github.com/derekparker/delve/pkg/proc/mach_exc.h b/vendor/github.com/derekparker/delve/pkg/proc/mach_exc.h new file mode 100644 index 0000000..b5f6dfc --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/mach_exc.h @@ -0,0 +1,283 @@ +#ifndef _mach_exc_user_ +#define _mach_exc_user_ + +/* Module mach_exc */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* BEGIN VOUCHER CODE */ + +#ifndef KERNEL +#if defined(__has_include) +#if __has_include() +#ifndef USING_VOUCHERS +#define USING_VOUCHERS +#endif +#ifndef __VOUCHER_FORWARD_TYPE_DECLS__ +#define __VOUCHER_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif // __VOUCHER_FORWARD_TYPE_DECLS__ +#endif // __has_include() +#endif // __has_include +#endif // !KERNEL + +/* END VOUCHER CODE */ + + +#ifdef AUTOTEST +#ifndef FUNCTION_PTR_T +#define FUNCTION_PTR_T +typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); +typedef struct { + char *name; + function_ptr_t function; +} function_table_entry; +typedef function_table_entry *function_table_t; +#endif /* FUNCTION_PTR_T */ +#endif /* AUTOTEST */ + +#ifndef mach_exc_MSG_COUNT +#define mach_exc_MSG_COUNT 3 +#endif /* mach_exc_MSG_COUNT */ + +#include +#include +#include +#include + +#ifdef __BeforeMigUserHeader +__BeforeMigUserHeader +#endif /* __BeforeMigUserHeader */ + +#include +__BEGIN_DECLS + + +/* Routine mach_exception_raise */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt +); + +/* Routine mach_exception_raise_state */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_state +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine mach_exception_raise_state_identity */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_state_identity +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +__END_DECLS + +/********************** Caution **************************/ +/* The following data types should be used to calculate */ +/* maximum message sizes only. The actual message may be */ +/* smaller, and the position of the arguments within the */ +/* message layout may vary from what is presented here. */ +/* For example, if any of the arguments are variable- */ +/* sized, and less than the maximum is sent, the data */ +/* will be packed tight in the actual message to reduce */ +/* the presence of holes. */ +/********************** Caution **************************/ + +/* typedefs for all requests */ + +#ifndef __Request__mach_exc_subsystem__defined +#define __Request__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } __Request__mach_exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } __Request__mach_exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } __Request__mach_exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Request__mach_exc_subsystem__defined */ + +/* union of all requests */ + +#ifndef __RequestUnion__mach_exc_subsystem__defined +#define __RequestUnion__mach_exc_subsystem__defined +union __RequestUnion__mach_exc_subsystem { + __Request__mach_exception_raise_t Request_mach_exception_raise; + __Request__mach_exception_raise_state_t Request_mach_exception_raise_state; + __Request__mach_exception_raise_state_identity_t Request_mach_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__mach_exc_subsystem__defined */ +/* typedefs for all replies */ + +#ifndef __Reply__mach_exc_subsystem__defined +#define __Reply__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__mach_exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply__mach_exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply__mach_exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Reply__mach_exc_subsystem__defined */ + +/* union of all replies */ + +#ifndef __ReplyUnion__mach_exc_subsystem__defined +#define __ReplyUnion__mach_exc_subsystem__defined +union __ReplyUnion__mach_exc_subsystem { + __Reply__mach_exception_raise_t Reply_mach_exception_raise; + __Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state; + __Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__mach_exc_subsystem__defined */ + +#ifndef subsystem_to_name_map_mach_exc +#define subsystem_to_name_map_mach_exc \ + { "mach_exception_raise", 2401 },\ + { "mach_exception_raise_state", 2402 },\ + { "mach_exception_raise_state_identity", 2403 } +#endif + +#ifdef __AfterMigUserHeader +__AfterMigUserHeader +#endif /* __AfterMigUserHeader */ + +#endif /* _mach_exc_user_ */ diff --git a/vendor/github.com/derekparker/delve/pkg/proc/mach_exc_user_darwin.c b/vendor/github.com/derekparker/delve/pkg/proc/mach_exc_user_darwin.c new file mode 100644 index 0000000..e475808 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/mach_exc_user_darwin.c @@ -0,0 +1,768 @@ +/* + * IDENTIFICATION: + * stub generated Sat Feb 21 18:10:52 2015 + * with a MiG generated by bootstrap_cmds-91 + * OPTIONS: + */ +#define __MIG_check__Reply__mach_exc_subsystem__ 1 + +#include "mach_exc.h" + + +#ifndef mig_internal +#define mig_internal static __inline__ +#endif /* mig_internal */ + +#ifndef mig_external +#define mig_external +#endif /* mig_external */ + +#if !defined(__MigTypeCheck) && defined(TypeCheck) +#define __MigTypeCheck TypeCheck /* Legacy setting */ +#endif /* !defined(__MigTypeCheck) */ + +#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_) +#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */ +#endif /* !defined(__MigKernelSpecificCode) */ + +#ifndef LimitCheck +#define LimitCheck 0 +#endif /* LimitCheck */ + +#ifndef min +#define min(a,b) ( ((a) < (b))? (a): (b) ) +#endif /* min */ + +#if !defined(_WALIGN_) +#define _WALIGN_(x) (((x) + 3) & ~3) +#endif /* !defined(_WALIGN_) */ + +#if !defined(_WALIGNSZ_) +#define _WALIGNSZ_(x) _WALIGN_(sizeof(x)) +#endif /* !defined(_WALIGNSZ_) */ + +#ifndef UseStaticTemplates +#define UseStaticTemplates 0 +#endif /* UseStaticTemplates */ + +#ifndef __MachMsgErrorWithTimeout +#define __MachMsgErrorWithTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + case MACH_SEND_TIMED_OUT: \ + case MACH_RCV_TIMED_OUT: \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithTimeout */ + +#ifndef __MachMsgErrorWithoutTimeout +#define __MachMsgErrorWithoutTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithoutTimeout */ + +#ifndef __DeclareSendRpc +#define __DeclareSendRpc(_NUM_, _NAME_) +#endif /* __DeclareSendRpc */ + +#ifndef __BeforeSendRpc +#define __BeforeSendRpc(_NUM_, _NAME_) +#endif /* __BeforeSendRpc */ + +#ifndef __AfterSendRpc +#define __AfterSendRpc(_NUM_, _NAME_) +#endif /* __AfterSendRpc */ + +#ifndef __DeclareSendSimple +#define __DeclareSendSimple(_NUM_, _NAME_) +#endif /* __DeclareSendSimple */ + +#ifndef __BeforeSendSimple +#define __BeforeSendSimple(_NUM_, _NAME_) +#endif /* __BeforeSendSimple */ + +#ifndef __AfterSendSimple +#define __AfterSendSimple(_NUM_, _NAME_) +#endif /* __AfterSendSimple */ + +#define msgh_request_port msgh_remote_port +#define msgh_reply_port msgh_local_port + + + +#if ( __MigTypeCheck ) +#if __MIG_check__Reply__mach_exc_subsystem__ +#if !defined(__MIG_check__Reply__mach_exception_raise_t__defined) +#define __MIG_check__Reply__mach_exception_raise_t__defined + +mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_t(__Reply__mach_exception_raise_t *Out0P) +{ + + typedef __Reply__mach_exception_raise_t __Reply; + if (Out0P->Head.msgh_id != 2505) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + { + return Out0P->RetCode; + } +} +#endif /* !defined(__MIG_check__Reply__mach_exception_raise_t__defined) */ +#endif /* __MIG_check__Reply__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine mach_exception_raise */ +mig_external kern_return_t mach_exception_raise +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } Request; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_trailer_t trailer; + } Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + +#ifdef __MIG_check__Reply__mach_exception_raise_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__mach_exception_raise_t__defined */ + + __DeclareSendRpc(2405, "mach_exception_raise") + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t threadTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t taskTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 2; +#if UseStaticTemplates + InP->thread = threadTemplate; + InP->thread.name = thread; +#else /* UseStaticTemplates */ + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + InP->task = taskTemplate; + InP->task.name = task; +#else /* UseStaticTemplates */ + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size = (mach_msg_size_t)(sizeof(Request) - 16) + ((8 * codeCnt)); + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2405; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2405, "mach_exception_raise") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2405, "mach_exception_raise") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__mach_exception_raise_t__defined) + check_result = __MIG_check__Reply__mach_exception_raise_t((__Reply__mach_exception_raise_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__mach_exception_raise_t__defined) */ + + return KERN_SUCCESS; +} + +#if ( __MigTypeCheck ) +#if __MIG_check__Reply__mach_exc_subsystem__ +#if !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) +#define __MIG_check__Reply__mach_exception_raise_state_t__defined + +mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_t(__Reply__mach_exception_raise_state_t *Out0P) +{ + + typedef __Reply__mach_exception_raise_state_t __Reply; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + + if (Out0P->Head.msgh_id != 2506) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + msgh_size = Out0P->Head.msgh_size; + + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) && + (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) || + Out0P->RetCode == KERN_SUCCESS))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + if (Out0P->RetCode != KERN_SUCCESS) { + return ((mig_reply_error_t *)Out0P)->RetCode; + } + +#if __MigTypeCheck + if ( Out0P->new_stateCnt > 224 ) + return MIG_TYPE_ERROR; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4)) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */ +#endif /* __MIG_check__Reply__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine mach_exception_raise_state */ +mig_external kern_return_t mach_exception_raise_state +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } Request; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + mach_msg_trailer_t trailer; + } Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + +#ifdef __MIG_check__Reply__mach_exception_raise_state_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__mach_exception_raise_state_t__defined */ + + __DeclareSendRpc(2406, "mach_exception_raise_state") + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size_delta = (8 * codeCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 912) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16); + + InP->flavor = *flavor; + + if (old_stateCnt > 224) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); + + InP->old_stateCnt = old_stateCnt; + + msgh_size += (4 * old_stateCnt); + InP = &Mess.In; + InP->Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2406; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2406, "mach_exception_raise_state") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2406, "mach_exception_raise_state") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) + check_result = __MIG_check__Reply__mach_exception_raise_state_t((__Reply__mach_exception_raise_state_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */ + + *flavor = Out0P->flavor; + + if (Out0P->new_stateCnt > 224) { + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224); + *new_stateCnt = Out0P->new_stateCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); + + *new_stateCnt = Out0P->new_stateCnt; + + return KERN_SUCCESS; +} + +#if ( __MigTypeCheck ) +#if __MIG_check__Reply__mach_exc_subsystem__ +#if !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) +#define __MIG_check__Reply__mach_exception_raise_state_identity_t__defined + +mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_identity_t(__Reply__mach_exception_raise_state_identity_t *Out0P) +{ + + typedef __Reply__mach_exception_raise_state_identity_t __Reply; +#if __MigTypeCheck + unsigned int msgh_size; +#endif /* __MigTypeCheck */ + + if (Out0P->Head.msgh_id != 2507) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + msgh_size = Out0P->Head.msgh_size; + + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 896)) && + (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) || + Out0P->RetCode == KERN_SUCCESS))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + if (Out0P->RetCode != KERN_SUCCESS) { + return ((mig_reply_error_t *)Out0P)->RetCode; + } + +#if __MigTypeCheck + if ( Out0P->new_stateCnt > 224 ) + return MIG_TYPE_ERROR; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 896)) / 4< Out0P->new_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 896) + Out0P->new_stateCnt * 4)) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */ +#endif /* __MIG_check__Reply__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck ) */ + + +/* Routine mach_exception_raise_state_identity */ +mig_external kern_return_t mach_exception_raise_state_identity +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[224]; + } Request; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + mach_msg_trailer_t trailer; + } Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[224]; + } __Reply; +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + +#ifdef __MIG_check__Reply__mach_exception_raise_state_identity_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__mach_exception_raise_state_identity_t__defined */ + + __DeclareSendRpc(2407, "mach_exception_raise_state_identity") + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t threadTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + const static mach_msg_port_descriptor_t taskTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 2; +#if UseStaticTemplates + InP->thread = threadTemplate; + InP->thread.name = thread; +#else /* UseStaticTemplates */ + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + +#if UseStaticTemplates + InP->task = taskTemplate; + InP->task.name = task; +#else /* UseStaticTemplates */ + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; +#endif /* UseStaticTemplates */ + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size_delta = (8 * codeCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 912) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16); + + InP->flavor = *flavor; + + if (old_stateCnt > 224) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); + + InP->old_stateCnt = old_stateCnt; + + msgh_size += (4 * old_stateCnt); + InP = &Mess.In; + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2407; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2407, "mach_exception_raise_state_identity") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2407, "mach_exception_raise_state_identity") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) + check_result = __MIG_check__Reply__mach_exception_raise_state_identity_t((__Reply__mach_exception_raise_state_identity_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */ + + *flavor = Out0P->flavor; + + if (Out0P->new_stateCnt > 224) { + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 224); + *new_stateCnt = Out0P->new_stateCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); + + *new_stateCnt = Out0P->new_stateCnt; + + return KERN_SUCCESS; +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/mem.go b/vendor/github.com/derekparker/delve/pkg/proc/mem.go new file mode 100644 index 0000000..ea45360 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/mem.go @@ -0,0 +1,57 @@ +package proc + +const cacheEnabled = true + +type memoryReadWriter interface { + readMemory(addr uintptr, size int) (data []byte, err error) + writeMemory(addr uintptr, data []byte) (written int, err error) +} + +type memCache struct { + cacheAddr uintptr + cache []byte + mem memoryReadWriter +} + +func (m *memCache) contains(addr uintptr, size int) bool { + return addr >= m.cacheAddr && addr <= (m.cacheAddr+uintptr(len(m.cache)-size)) +} + +func (m *memCache) readMemory(addr uintptr, size int) (data []byte, err error) { + if m.contains(addr, size) { + d := make([]byte, size) + copy(d, m.cache[addr-m.cacheAddr:]) + return d, nil + } + + return m.mem.readMemory(addr, size) +} + +func (m *memCache) writeMemory(addr uintptr, data []byte) (written int, err error) { + return m.mem.writeMemory(addr, data) +} + +func cacheMemory(mem memoryReadWriter, addr uintptr, size int) memoryReadWriter { + if !cacheEnabled { + return mem + } + if size <= 0 { + return mem + } + if cacheMem, isCache := mem.(*memCache); isCache { + if cacheMem.contains(addr, size) { + return mem + } else { + cache, err := cacheMem.mem.readMemory(addr, size) + if err != nil { + return mem + } + return &memCache{addr, cache, mem} + } + } + cache, err := mem.readMemory(addr, size) + if err != nil { + return mem + } + return &memCache{addr, cache, mem} +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/moduledata.go b/vendor/github.com/derekparker/delve/pkg/proc/moduledata.go new file mode 100644 index 0000000..ae9d840 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/moduledata.go @@ -0,0 +1,189 @@ +package proc + +import ( + "go/constant" + "unsafe" +) + +// delve counterpart to runtime.moduledata +type moduleData struct { + types, etypes uintptr + typemapVar *Variable +} + +func (dbp *Process) loadModuleData() (err error) { + dbp.loadModuleDataOnce.Do(func() { + scope := &EvalScope{Thread: dbp.currentThread, PC: 0, CFA: 0} + var md *Variable + md, err = scope.packageVarAddr("runtime.firstmoduledata") + if err != nil { + return + } + + for md.Addr != 0 { + var typesVar, etypesVar, nextVar, typemapVar *Variable + var types, etypes uint64 + + if typesVar, err = md.structMember("types"); err != nil { + return + } + if etypesVar, err = md.structMember("etypes"); err != nil { + return + } + if nextVar, err = md.structMember("next"); err != nil { + return + } + if typemapVar, err = md.structMember("typemap"); err != nil { + return + } + if types, err = typesVar.asUint(); err != nil { + return + } + if etypes, err = etypesVar.asUint(); err != nil { + return + } + + dbp.moduleData = append(dbp.moduleData, moduleData{uintptr(types), uintptr(etypes), typemapVar}) + + md = nextVar.maybeDereference() + if md.Unreadable != nil { + err = md.Unreadable + return + } + } + }) + + return +} + +func (dbp *Process) resolveTypeOff(typeAddr uintptr, off uintptr) (*Variable, error) { + // See runtime.(*_type).typeOff in $GOROOT/src/runtime/type.go + if err := dbp.loadModuleData(); err != nil { + return nil, err + } + + var md *moduleData + for i := range dbp.moduleData { + if typeAddr >= dbp.moduleData[i].types && typeAddr < dbp.moduleData[i].etypes { + md = &dbp.moduleData[i] + } + } + + rtyp, err := dbp.findType("runtime._type") + if err != nil { + return nil, err + } + + if md == nil { + v, err := dbp.reflectOffsMapAccess(off) + if err != nil { + return nil, err + } + v.loadValue(LoadConfig{false, 1, 0, 0, -1}) + addr, _ := constant.Int64Val(v.Value) + return v.newVariable(v.Name, uintptr(addr), rtyp), nil + } + + if t, _ := md.typemapVar.mapAccess(newConstant(constant.MakeUint64(uint64(off)), dbp.currentThread)); t != nil { + return t, nil + } + + res := md.types + uintptr(off) + + return dbp.currentThread.newVariable("", res, rtyp), nil +} + +func (dbp *Process) resolveNameOff(typeAddr uintptr, off uintptr) (name, tag string, pkgpathoff int32, err error) { + // See runtime.resolveNameOff in $GOROOT/src/runtime/type.go + if err = dbp.loadModuleData(); err != nil { + return "", "", 0, err + } + + for _, md := range dbp.moduleData { + if typeAddr >= md.types && typeAddr < md.etypes { + return dbp.loadName(md.types + off) + } + } + + v, err := dbp.reflectOffsMapAccess(off) + if err != nil { + return "", "", 0, err + } + + resv := v.maybeDereference() + if resv.Unreadable != nil { + return "", "", 0, resv.Unreadable + } + + return dbp.loadName(resv.Addr) +} + +func (dbp *Process) reflectOffsMapAccess(off uintptr) (*Variable, error) { + scope := &EvalScope{Thread: dbp.currentThread, PC: 0, CFA: 0} + reflectOffs, err := scope.packageVarAddr("runtime.reflectOffs") + if err != nil { + return nil, err + } + + reflectOffsm, err := reflectOffs.structMember("m") + if err != nil { + return nil, err + } + + return reflectOffsm.mapAccess(newConstant(constant.MakeUint64(uint64(off)), dbp.currentThread)) +} + +const ( + // flags for the name struct (see 'type name struct' in $GOROOT/src/reflect/type.go) + nameflagExported = 1 << 0 + nameflagHasTag = 1 << 1 + nameflagHasPkg = 1 << 2 +) + +func (dbp *Process) loadName(addr uintptr) (name, tag string, pkgpathoff int32, err error) { + off := addr + namedata, err := dbp.currentThread.readMemory(off, 3) + off += 3 + if err != nil { + return "", "", 0, err + } + + namelen := uint16(namedata[1]<<8) | uint16(namedata[2]) + + rawstr, err := dbp.currentThread.readMemory(off, int(namelen)) + off += uintptr(namelen) + if err != nil { + return "", "", 0, err + } + + name = string(rawstr) + + if namedata[0]&nameflagHasTag != 0 { + taglendata, err := dbp.currentThread.readMemory(off, 2) + off += 2 + if err != nil { + return "", "", 0, err + } + taglen := uint16(taglendata[0]<<8) | uint16(taglendata[1]) + + rawstr, err := dbp.currentThread.readMemory(off, int(taglen)) + off += uintptr(taglen) + if err != nil { + return "", "", 0, err + } + + tag = string(rawstr) + } + + if namedata[0]&nameflagHasPkg != 0 { + pkgdata, err := dbp.currentThread.readMemory(off, 4) + if err != nil { + return "", "", 0, err + } + + // see func pkgPath in $GOROOT/src/reflect/type.go + copy((*[4]byte)(unsafe.Pointer(&pkgpathoff))[:], pkgdata) + } + + return name, tag, pkgpathoff, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/proc.go b/vendor/github.com/derekparker/delve/pkg/proc/proc.go new file mode 100644 index 0000000..de9aa63 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/proc.go @@ -0,0 +1,986 @@ +package proc + +import ( + "debug/gosym" + "encoding/binary" + "errors" + "fmt" + "go/ast" + "go/constant" + "go/token" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "time" + + "github.com/derekparker/delve/pkg/dwarf/frame" + "github.com/derekparker/delve/pkg/dwarf/line" + "github.com/derekparker/delve/pkg/dwarf/reader" + "golang.org/x/debug/dwarf" +) + +// Process represents all of the information the debugger +// is holding onto regarding the process we are debugging. +type Process struct { + pid int // Process Pid + Process *os.Process // Pointer to process struct for the actual process we are debugging + lastModified time.Time // Time the executable of this process was last modified + + // Breakpoint table, holds information on breakpoints. + // Maps instruction address to Breakpoint struct. + breakpoints map[uint64]*Breakpoint + + // List of threads mapped as such: pid -> *Thread + threads map[int]*Thread + + // Active thread + currentThread *Thread + + // Goroutine that will be used by default to set breakpoint, eval variables, etc... + // Normally selectedGoroutine is currentThread.GetG, it will not be only if SwitchGoroutine is called with a goroutine that isn't attached to a thread + selectedGoroutine *G + + // Maps package names to package paths, needed to lookup types inside DWARF info + packageMap map[string]string + + allGCache []*G + dwarf *dwarf.Data + goSymTable *gosym.Table + frameEntries frame.FrameDescriptionEntries + lineInfo line.DebugLines + os *OSProcessDetails + arch Arch + breakpointIDCounter int + internalBreakpointIDCounter int + firstStart bool + halt bool + exited bool + ptraceChan chan func() + ptraceDoneChan chan interface{} + types map[string]dwarf.Offset + functions []functionDebugInfo + + loadModuleDataOnce sync.Once + moduleData []moduleData + nameOfRuntimeType map[uintptr]nameOfRuntimeTypeEntry +} + +type functionDebugInfo struct { + lowpc, highpc uint64 + offset dwarf.Offset +} + +var NotExecutableErr = errors.New("not an executable file") + +// New returns an initialized Process struct. Before returning, +// it will also launch a goroutine in order to handle ptrace(2) +// functions. For more information, see the documentation on +// `handlePtraceFuncs`. +func New(pid int) *Process { + dbp := &Process{ + pid: pid, + threads: make(map[int]*Thread), + breakpoints: make(map[uint64]*Breakpoint), + firstStart: true, + os: new(OSProcessDetails), + ptraceChan: make(chan func()), + ptraceDoneChan: make(chan interface{}), + nameOfRuntimeType: make(map[uintptr]nameOfRuntimeTypeEntry), + } + // TODO: find better way to determine proc arch (perhaps use executable file info) + switch runtime.GOARCH { + case "amd64": + dbp.arch = AMD64Arch() + } + go dbp.handlePtraceFuncs() + return dbp +} + +// ProcessExitedError indicates that the process has exited and contains both +// process id and exit status. +type ProcessExitedError struct { + Pid int + Status int +} + +func (pe ProcessExitedError) Error() string { + return fmt.Sprintf("Process %d has exited with status %d", pe.Pid, pe.Status) +} + +// Detach from the process being debugged, optionally killing it. +func (dbp *Process) Detach(kill bool) (err error) { + if dbp.exited { + return nil + } + if dbp.Running() { + if err = dbp.Halt(); err != nil { + return + } + } + if !kill { + // Clean up any breakpoints we've set. + for _, bp := range dbp.breakpoints { + if bp != nil { + _, err := dbp.ClearBreakpoint(bp.Addr) + if err != nil { + return err + } + } + } + } + dbp.execPtraceFunc(func() { + err = PtraceDetach(dbp.pid, 0) + if err != nil { + return + } + if kill { + err = killProcess(dbp.pid) + } + }) + return +} + +// Exited returns whether the debugged +// process has exited. +func (dbp *Process) Exited() bool { + return dbp.exited +} + +// Running returns whether the debugged +// process is currently executing. +func (dbp *Process) Running() bool { + for _, th := range dbp.threads { + if th.running { + return true + } + } + return false +} + +func (dbp *Process) LastModified() time.Time { + return dbp.lastModified +} + +func (dbp *Process) Pid() int { + return dbp.pid +} + +func (dbp *Process) SelectedGoroutine() *G { + return dbp.selectedGoroutine +} + +func (dbp *Process) Threads() map[int]*Thread { + return dbp.threads +} + +func (dbp *Process) CurrentThread() *Thread { + return dbp.currentThread +} + +func (dbp *Process) Breakpoints() map[uint64]*Breakpoint { + return dbp.breakpoints +} + +// LoadInformation finds the executable and then uses it +// to parse the following information: +// * Dwarf .debug_frame section +// * Dwarf .debug_line section +// * Go symbol table. +func (dbp *Process) LoadInformation(path string) error { + var wg sync.WaitGroup + + exe, path, err := dbp.findExecutable(path) + if err != nil { + return err + } + fi, err := os.Stat(path) + if err == nil { + dbp.lastModified = fi.ModTime() + } + + wg.Add(5) + go dbp.loadProcessInformation(&wg) + go dbp.parseDebugFrame(exe, &wg) + go dbp.obtainGoSymbols(exe, &wg) + go dbp.parseDebugLineInfo(exe, &wg) + go dbp.loadDebugInfoMaps(&wg) + wg.Wait() + + return nil +} + +// FindFileLocation returns the PC for a given file:line. +// Assumes that `file` is normailzed to lower case and '/' on Windows. +func (dbp *Process) FindFileLocation(fileName string, lineno int) (uint64, error) { + pc, fn, err := dbp.goSymTable.LineToPC(fileName, lineno) + if err != nil { + return 0, err + } + if fn.Entry == pc { + pc, _ = dbp.FirstPCAfterPrologue(fn, true) + } + return pc, nil +} + +// FindFunctionLocation finds address of a function's line +// If firstLine == true is passed FindFunctionLocation will attempt to find the first line of the function +// If lineOffset is passed FindFunctionLocation will return the address of that line +// Pass lineOffset == 0 and firstLine == false if you want the address for the function's entry point +// Note that setting breakpoints at that address will cause surprising behavior: +// https://github.com/derekparker/delve/issues/170 +func (dbp *Process) FindFunctionLocation(funcName string, firstLine bool, lineOffset int) (uint64, error) { + origfn := dbp.goSymTable.LookupFunc(funcName) + if origfn == nil { + return 0, fmt.Errorf("Could not find function %s\n", funcName) + } + + if firstLine { + return dbp.FirstPCAfterPrologue(origfn, false) + } else if lineOffset > 0 { + filename, lineno, _ := dbp.goSymTable.PCToLine(origfn.Entry) + breakAddr, _, err := dbp.goSymTable.LineToPC(filename, lineno+lineOffset) + return breakAddr, err + } + + return origfn.Entry, nil +} + +// CurrentLocation returns the location of the current thread. +func (dbp *Process) CurrentLocation() (*Location, error) { + return dbp.currentThread.Location() +} + +// RequestManualStop sets the `halt` flag and +// sends SIGSTOP to all threads. +func (dbp *Process) RequestManualStop() error { + if dbp.exited { + return &ProcessExitedError{} + } + dbp.halt = true + return dbp.requestManualStop() +} + +// SetBreakpoint sets a breakpoint at addr, and stores it in the process wide +// break point table. Setting a break point must be thread specific due to +// ptrace actions needing the thread to be in a signal-delivery-stop. +func (dbp *Process) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error) { + tid := dbp.currentThread.ID + + if bp, ok := dbp.FindBreakpoint(addr); ok { + return nil, BreakpointExistsError{bp.File, bp.Line, bp.Addr} + } + + f, l, fn := dbp.goSymTable.PCToLine(uint64(addr)) + if fn == nil { + return nil, InvalidAddressError{address: addr} + } + + newBreakpoint := &Breakpoint{ + FunctionName: fn.Name, + File: f, + Line: l, + Addr: addr, + Kind: kind, + Cond: cond, + HitCount: map[int]uint64{}, + } + + if kind != UserBreakpoint { + dbp.internalBreakpointIDCounter++ + newBreakpoint.ID = dbp.internalBreakpointIDCounter + } else { + dbp.breakpointIDCounter++ + newBreakpoint.ID = dbp.breakpointIDCounter + } + + thread := dbp.threads[tid] + originalData, err := thread.readMemory(uintptr(addr), dbp.arch.BreakpointSize()) + if err != nil { + return nil, err + } + if err := dbp.writeSoftwareBreakpoint(thread, addr); err != nil { + return nil, err + } + newBreakpoint.OriginalData = originalData + dbp.breakpoints[addr] = newBreakpoint + + return newBreakpoint, nil +} + +// ClearBreakpoint clears the breakpoint at addr. +func (dbp *Process) ClearBreakpoint(addr uint64) (*Breakpoint, error) { + if dbp.exited { + return nil, &ProcessExitedError{} + } + bp, ok := dbp.FindBreakpoint(addr) + if !ok { + return nil, NoBreakpointError{addr: addr} + } + + if _, err := bp.Clear(dbp.currentThread); err != nil { + return nil, err + } + + delete(dbp.breakpoints, addr) + + return bp, nil +} + +// Status returns the status of the current main thread context. +func (dbp *Process) Status() *WaitStatus { + return dbp.currentThread.Status +} + +// Next continues execution until the next source line. +func (dbp *Process) Next() (err error) { + if dbp.exited { + return &ProcessExitedError{} + } + for i := range dbp.breakpoints { + if dbp.breakpoints[i].Internal() { + return fmt.Errorf("next while nexting") + } + } + + if err = dbp.next(false); err != nil { + switch err.(type) { + case ThreadBlockedError, NoReturnAddr: // Noop + default: + dbp.ClearInternalBreakpoints() + return + } + } + + return dbp.Continue() +} + +// Continue continues execution of the debugged +// process. It will continue until it hits a breakpoint +// or is otherwise stopped. +func (dbp *Process) Continue() error { + if dbp.exited { + return &ProcessExitedError{} + } + for { + if err := dbp.resume(); err != nil { + return err + } + + dbp.allGCache = nil + for _, th := range dbp.threads { + th.clearBreakpointState() + } + + trapthread, err := dbp.trapWait(-1) + if err != nil { + return err + } + if err := dbp.Halt(); err != nil { + return dbp.exitGuard(err) + } + if err := dbp.setCurrentBreakpoints(trapthread); err != nil { + return err + } + if err := dbp.pickCurrentThread(trapthread); err != nil { + return err + } + + switch { + case dbp.currentThread.CurrentBreakpoint == nil: + // runtime.Breakpoint or manual stop + if dbp.currentThread.onRuntimeBreakpoint() { + // Single-step current thread until we exit runtime.breakpoint and + // runtime.Breakpoint. + // On go < 1.8 it was sufficient to single-step twice on go1.8 a change + // to the compiler requires 4 steps. + for { + if err = dbp.currentThread.StepInstruction(); err != nil { + return err + } + loc, err := dbp.currentThread.Location() + if err != nil || loc.Fn == nil || (loc.Fn.Name != "runtime.breakpoint" && loc.Fn.Name != "runtime.Breakpoint") { + break + } + } + } + return dbp.conditionErrors() + case dbp.currentThread.onTriggeredInternalBreakpoint(): + if dbp.currentThread.CurrentBreakpoint.Kind == StepBreakpoint { + // See description of proc.(*Process).next for the meaning of StepBreakpoints + if err := dbp.conditionErrors(); err != nil { + return err + } + pc, err := dbp.currentThread.PC() + if err != nil { + return err + } + text, err := dbp.currentThread.Disassemble(pc, pc+maxInstructionLength, true) + if err != nil { + return err + } + // here we either set a breakpoint into the destination of the CALL + // instruction or we determined that the called function is hidden, + // either way we need to resume execution + if err = dbp.setStepIntoBreakpoint(text, sameGoroutineCondition(dbp.selectedGoroutine)); err != nil { + return err + } + } else { + if err := dbp.ClearInternalBreakpoints(); err != nil { + return err + } + return dbp.conditionErrors() + } + case dbp.currentThread.onTriggeredBreakpoint(): + onNextGoroutine, err := dbp.currentThread.onNextGoroutine() + if err != nil { + return err + } + if onNextGoroutine { + err := dbp.ClearInternalBreakpoints() + if err != nil { + return err + } + } + return dbp.conditionErrors() + default: + // not a manual stop, not on runtime.Breakpoint, not on a breakpoint, just repeat + } + } +} + +func (dbp *Process) conditionErrors() error { + var condErr error + for _, th := range dbp.threads { + if th.CurrentBreakpoint != nil && th.BreakpointConditionError != nil { + if condErr == nil { + condErr = th.BreakpointConditionError + } else { + return fmt.Errorf("multiple errors evaluating conditions") + } + } + } + return condErr +} + +// pick a new dbp.currentThread, with the following priority: +// - a thread with onTriggeredInternalBreakpoint() == true +// - a thread with onTriggeredBreakpoint() == true (prioritizing trapthread) +// - trapthread +func (dbp *Process) pickCurrentThread(trapthread *Thread) error { + for _, th := range dbp.threads { + if th.onTriggeredInternalBreakpoint() { + return dbp.SwitchThread(th.ID) + } + } + if trapthread.onTriggeredBreakpoint() { + return dbp.SwitchThread(trapthread.ID) + } + for _, th := range dbp.threads { + if th.onTriggeredBreakpoint() { + return dbp.SwitchThread(th.ID) + } + } + return dbp.SwitchThread(trapthread.ID) +} + +// Step will continue until another source line is reached. +// Will step into functions. +func (dbp *Process) Step() (err error) { + if dbp.exited { + return &ProcessExitedError{} + } + for i := range dbp.breakpoints { + if dbp.breakpoints[i].Internal() { + return fmt.Errorf("next while nexting") + } + } + + if err = dbp.next(true); err != nil { + switch err.(type) { + case ThreadBlockedError, NoReturnAddr: // Noop + default: + dbp.ClearInternalBreakpoints() + return + } + } + + return dbp.Continue() +} + +// Returns an expression that evaluates to true when the current goroutine is g +func sameGoroutineCondition(g *G) ast.Expr { + if g == nil { + return nil + } + return &ast.BinaryExpr{ + Op: token.EQL, + X: &ast.SelectorExpr{ + X: &ast.SelectorExpr{ + X: &ast.Ident{Name: "runtime"}, + Sel: &ast.Ident{Name: "curg"}, + }, + Sel: &ast.Ident{Name: "goid"}, + }, + Y: &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(g.ID)}, + } +} + +// StepInstruction will continue the current thread for exactly +// one instruction. This method affects only the thread +// asssociated with the selected goroutine. All other +// threads will remain stopped. +func (dbp *Process) StepInstruction() (err error) { + if dbp.selectedGoroutine == nil { + return errors.New("cannot single step: no selected goroutine") + } + if dbp.selectedGoroutine.thread == nil { + // Step called on parked goroutine + if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, NextBreakpoint, sameGoroutineCondition(dbp.selectedGoroutine)); err != nil { + return err + } + return dbp.Continue() + } + dbp.allGCache = nil + if dbp.exited { + return &ProcessExitedError{} + } + dbp.selectedGoroutine.thread.clearBreakpointState() + err = dbp.selectedGoroutine.thread.StepInstruction() + if err != nil { + return err + } + return dbp.selectedGoroutine.thread.SetCurrentBreakpoint() +} + +// StepOut will continue until the current goroutine exits the +// function currently being executed or a deferred function is executed +func (dbp *Process) StepOut() error { + cond := sameGoroutineCondition(dbp.selectedGoroutine) + + topframe, err := topframe(dbp.selectedGoroutine, dbp.currentThread) + if err != nil { + return err + } + + pcs := []uint64{} + + var deferpc uint64 = 0 + if filepath.Ext(topframe.Current.File) == ".go" { + if dbp.selectedGoroutine != nil { + deferPCEntry := dbp.selectedGoroutine.DeferPC() + if deferPCEntry != 0 { + _, _, deferfn := dbp.goSymTable.PCToLine(deferPCEntry) + deferpc, err = dbp.FirstPCAfterPrologue(deferfn, false) + if err != nil { + return err + } + pcs = append(pcs, deferpc) + } + } + } + + if topframe.Ret == 0 && deferpc == 0 { + return errors.New("nothing to stepout to") + } + + if deferpc != 0 && deferpc != topframe.Current.PC { + bp, err := dbp.SetBreakpoint(deferpc, NextDeferBreakpoint, cond) + if err != nil { + if _, ok := err.(BreakpointExistsError); !ok { + dbp.ClearInternalBreakpoints() + return err + } + } + if bp != nil { + // For StepOut we do not want to step into the deferred function + // when it's called by runtime.deferreturn so we do not populate + // DeferReturns. + bp.DeferReturns = []uint64{} + } + } + + if topframe.Ret != 0 { + if err := dbp.setInternalBreakpoints(topframe.Current.PC, []uint64{topframe.Ret}, NextBreakpoint, cond); err != nil { + return err + } + } + + return dbp.Continue() +} + +// SwitchThread changes from current thread to the thread specified by `tid`. +func (dbp *Process) SwitchThread(tid int) error { + if dbp.exited { + return &ProcessExitedError{} + } + if th, ok := dbp.threads[tid]; ok { + dbp.currentThread = th + dbp.selectedGoroutine, _ = dbp.currentThread.GetG() + return nil + } + return fmt.Errorf("thread %d does not exist", tid) +} + +// SwitchGoroutine changes from current thread to the thread +// running the specified goroutine. +func (dbp *Process) SwitchGoroutine(gid int) error { + if dbp.exited { + return &ProcessExitedError{} + } + g, err := dbp.FindGoroutine(gid) + if err != nil { + return err + } + if g == nil { + // user specified -1 and selectedGoroutine is nil + return nil + } + if g.thread != nil { + return dbp.SwitchThread(g.thread.ID) + } + dbp.selectedGoroutine = g + return nil +} + +// GoroutinesInfo returns an array of G structures representing the information +// Delve cares about from the internal runtime G structure. +func (dbp *Process) GoroutinesInfo() ([]*G, error) { + if dbp.exited { + return nil, &ProcessExitedError{} + } + if dbp.allGCache != nil { + return dbp.allGCache, nil + } + + var ( + threadg = map[int]*Thread{} + allg []*G + rdr = dbp.DwarfReader() + ) + + for i := range dbp.threads { + if dbp.threads[i].blocked() { + continue + } + g, _ := dbp.threads[i].GetG() + if g != nil { + threadg[g.ID] = dbp.threads[i] + } + } + + addr, err := rdr.AddrFor("runtime.allglen") + if err != nil { + return nil, err + } + allglenBytes, err := dbp.currentThread.readMemory(uintptr(addr), 8) + if err != nil { + return nil, err + } + allglen := binary.LittleEndian.Uint64(allglenBytes) + + rdr.Seek(0) + allgentryaddr, err := rdr.AddrFor("runtime.allgs") + if err != nil { + // try old name (pre Go 1.6) + allgentryaddr, err = rdr.AddrFor("runtime.allg") + if err != nil { + return nil, err + } + } + faddr, err := dbp.currentThread.readMemory(uintptr(allgentryaddr), dbp.arch.PtrSize()) + allgptr := binary.LittleEndian.Uint64(faddr) + + for i := uint64(0); i < allglen; i++ { + gvar, err := dbp.currentThread.newGVariable(uintptr(allgptr+(i*uint64(dbp.arch.PtrSize()))), true) + if err != nil { + return nil, err + } + g, err := gvar.parseG() + if err != nil { + return nil, err + } + if thread, allocated := threadg[g.ID]; allocated { + loc, err := thread.Location() + if err != nil { + return nil, err + } + g.thread = thread + // Prefer actual thread location information. + g.CurrentLoc = *loc + } + if g.Status != Gdead { + allg = append(allg, g) + } + } + dbp.allGCache = allg + return allg, nil +} + +func (g *G) Thread() *Thread { + return g.thread +} + +// Halt stops all threads. +func (dbp *Process) Halt() (err error) { + if dbp.exited { + return &ProcessExitedError{} + } + for _, th := range dbp.threads { + if err := th.Halt(); err != nil { + return err + } + } + return nil +} + +// Registers obtains register values from the +// "current" thread of the traced process. +func (dbp *Process) Registers() (Registers, error) { + return dbp.currentThread.Registers(false) +} + +// PC returns the PC of the current thread. +func (dbp *Process) PC() (uint64, error) { + return dbp.currentThread.PC() +} + +// CurrentBreakpoint returns the breakpoint the current thread +// is stopped at. +func (dbp *Process) CurrentBreakpoint() *Breakpoint { + return dbp.currentThread.CurrentBreakpoint +} + +// DwarfReader returns a reader for the dwarf data +func (dbp *Process) DwarfReader() *reader.Reader { + return reader.New(dbp.dwarf) +} + +// Sources returns list of source files that comprise the debugged binary. +func (dbp *Process) Sources() map[string]*gosym.Obj { + return dbp.goSymTable.Files +} + +// Funcs returns list of functions present in the debugged program. +func (dbp *Process) Funcs() []gosym.Func { + return dbp.goSymTable.Funcs +} + +// Types returns list of types present in the debugged program. +func (dbp *Process) Types() ([]string, error) { + types := make([]string, 0, len(dbp.types)) + for k := range dbp.types { + types = append(types, k) + } + return types, nil +} + +// PCToLine converts an instruction address to a file/line/function. +func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) { + return dbp.goSymTable.PCToLine(pc) +} + +// FindBreakpointByID finds the breakpoint for the given ID. +func (dbp *Process) FindBreakpointByID(id int) (*Breakpoint, bool) { + for _, bp := range dbp.breakpoints { + if bp.ID == id { + return bp, true + } + } + return nil, false +} + +// FindBreakpoint finds the breakpoint for the given pc. +func (dbp *Process) FindBreakpoint(pc uint64) (*Breakpoint, bool) { + // Check to see if address is past the breakpoint, (i.e. breakpoint was hit). + if bp, ok := dbp.breakpoints[pc-uint64(dbp.arch.BreakpointSize())]; ok { + return bp, true + } + // Directly use addr to lookup breakpoint. + if bp, ok := dbp.breakpoints[pc]; ok { + return bp, true + } + return nil, false +} + +// Returns a new Process struct. +func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, error) { + if attach { + var err error + dbp.execPtraceFunc(func() { err = PtraceAttach(dbp.pid) }) + if err != nil { + return nil, err + } + _, _, err = dbp.wait(dbp.pid, 0) + if err != nil { + return nil, err + } + } + + proc, err := os.FindProcess(dbp.pid) + if err != nil { + return nil, err + } + + dbp.Process = proc + err = dbp.LoadInformation(path) + if err != nil { + return nil, err + } + + if err := dbp.updateThreadList(); err != nil { + return nil, err + } + + ver, isextld, err := dbp.getGoInformation() + if err != nil { + return nil, err + } + + dbp.arch.SetGStructOffset(ver, isextld) + // selectedGoroutine can not be set correctly by the call to updateThreadList + // because without calling SetGStructOffset we can not read the G struct of currentThread + // but without calling updateThreadList we can not examine memory to determine + // the offset of g struct inside TLS + dbp.selectedGoroutine, _ = dbp.currentThread.GetG() + + panicpc, err := dbp.FindFunctionLocation("runtime.startpanic", true, 0) + if err == nil { + bp, err := dbp.SetBreakpoint(panicpc, UserBreakpoint, nil) + if err == nil { + bp.Name = "unrecovered-panic" + bp.ID = -1 + dbp.breakpointIDCounter-- + } + } + + return dbp, nil +} + +func (dbp *Process) ClearInternalBreakpoints() error { + for _, bp := range dbp.breakpoints { + if !bp.Internal() { + continue + } + if _, err := dbp.ClearBreakpoint(bp.Addr); err != nil { + return err + } + } + for i := range dbp.threads { + if dbp.threads[i].CurrentBreakpoint != nil && dbp.threads[i].CurrentBreakpoint.Internal() { + dbp.threads[i].CurrentBreakpoint = nil + } + } + return nil +} + +func (dbp *Process) handlePtraceFuncs() { + // We must ensure here that we are running on the same thread during + // while invoking the ptrace(2) syscall. This is due to the fact that ptrace(2) expects + // all commands after PTRACE_ATTACH to come from the same thread. + runtime.LockOSThread() + + for fn := range dbp.ptraceChan { + fn() + dbp.ptraceDoneChan <- nil + } +} + +func (dbp *Process) execPtraceFunc(fn func()) { + dbp.ptraceChan <- fn + <-dbp.ptraceDoneChan +} + +func (dbp *Process) getGoInformation() (ver GoVersion, isextld bool, err error) { + vv, err := dbp.EvalPackageVariable("runtime.buildVersion", LoadConfig{true, 0, 64, 0, 0}) + if err != nil { + err = fmt.Errorf("Could not determine version number: %v\n", err) + return + } + if vv.Unreadable != nil { + err = fmt.Errorf("Unreadable version number: %v\n", vv.Unreadable) + return + } + + ver, ok := ParseVersionString(constant.StringVal(vv.Value)) + if !ok { + err = fmt.Errorf("Could not parse version number: %v\n", vv.Value) + return + } + + rdr := dbp.DwarfReader() + rdr.Seek(0) + for entry, err := rdr.NextCompileUnit(); entry != nil; entry, err = rdr.NextCompileUnit() { + if err != nil { + return ver, isextld, err + } + if prod, ok := entry.Val(dwarf.AttrProducer).(string); ok && (strings.HasPrefix(prod, "GNU AS")) { + isextld = true + break + } + } + return +} + +// FindGoroutine returns a G struct representing the goroutine +// specified by `gid`. +func (dbp *Process) FindGoroutine(gid int) (*G, error) { + if gid == -1 { + return dbp.selectedGoroutine, nil + } + + gs, err := dbp.GoroutinesInfo() + if err != nil { + return nil, err + } + for i := range gs { + if gs[i].ID == gid { + return gs[i], nil + } + } + return nil, fmt.Errorf("Unknown goroutine %d", gid) +} + +// ConvertEvalScope returns a new EvalScope in the context of the +// specified goroutine ID and stack frame. +func (dbp *Process) ConvertEvalScope(gid, frame int) (*EvalScope, error) { + if dbp.exited { + return nil, &ProcessExitedError{} + } + g, err := dbp.FindGoroutine(gid) + if err != nil { + return nil, err + } + if g == nil { + return dbp.currentThread.Scope() + } + + var out EvalScope + + if g.thread == nil { + out.Thread = dbp.currentThread + } else { + out.Thread = g.thread + } + + locs, err := g.Stacktrace(frame) + if err != nil { + return nil, err + } + + if frame >= len(locs) { + return nil, fmt.Errorf("Frame %d does not exist in goroutine %d", frame, gid) + } + + out.PC, out.CFA = locs[frame].Current.PC, locs[frame].CFA + + return &out, nil +} + +func (dbp *Process) postExit() { + dbp.exited = true + close(dbp.ptraceChan) + close(dbp.ptraceDoneChan) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.c b/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.c new file mode 100644 index 0000000..24a6084 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.c @@ -0,0 +1,231 @@ +#include "proc_darwin.h" + +static const unsigned char info_plist[] +__attribute__ ((section ("__TEXT,__info_plist"),used)) = +"\n" +"\n" +"\n" +"\n" +" CFBundleIdentifier\n" +" org.dlv\n" +" CFBundleName\n" +" delve\n" +" CFBundleVersion\n" +" 1.0\n" +" SecTaskAccess\n" +" \n" +" allowed\n" +" debug\n" +" \n" +"\n" +"\n"; + +kern_return_t +acquire_mach_task(int tid, + task_t *task, + mach_port_t *port_set, + mach_port_t *exception_port, + mach_port_t *notification_port) +{ + kern_return_t kret; + mach_port_t prev_not; + mach_port_t self = mach_task_self(); + + kret = task_for_pid(self, tid, task); + if (kret != KERN_SUCCESS) return kret; + + // Allocate exception port. + kret = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, exception_port); + if (kret != KERN_SUCCESS) return kret; + + kret = mach_port_insert_right(self, *exception_port, *exception_port, MACH_MSG_TYPE_MAKE_SEND); + if (kret != KERN_SUCCESS) return kret; + + kret = task_set_exception_ports(*task, EXC_MASK_BREAKPOINT|EXC_MASK_SOFTWARE, *exception_port, + EXCEPTION_DEFAULT, THREAD_STATE_NONE); + if (kret != KERN_SUCCESS) return kret; + + // Allocate notification port to alert of when the process dies. + kret = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, notification_port); + if (kret != KERN_SUCCESS) return kret; + + kret = mach_port_insert_right(self, *notification_port, *notification_port, MACH_MSG_TYPE_MAKE_SEND); + if (kret != KERN_SUCCESS) return kret; + + kret = mach_port_request_notification(self, *task, MACH_NOTIFY_DEAD_NAME, 0, *notification_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_not); + if (kret != KERN_SUCCESS) return kret; + + // Create port set. + kret = mach_port_allocate(self, MACH_PORT_RIGHT_PORT_SET, port_set); + if (kret != KERN_SUCCESS) return kret; + + // Move exception and notification ports to port set. + kret = mach_port_move_member(self, *exception_port, *port_set); + if (kret != KERN_SUCCESS) return kret; + + return mach_port_move_member(self, *notification_port, *port_set); +} + +kern_return_t +reset_exception_ports(task_t task, mach_port_t *exception_port, mach_port_t *notification_port) { + kern_return_t kret; + mach_port_t prev_not; + mach_port_t self = mach_task_self(); + + kret = task_set_exception_ports(task, EXC_MASK_BREAKPOINT|EXC_MASK_SOFTWARE, *exception_port, + EXCEPTION_DEFAULT, THREAD_STATE_NONE); + if (kret != KERN_SUCCESS) return kret; + + kret = mach_port_request_notification(self, task, MACH_NOTIFY_DEAD_NAME, 0, *notification_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_not); + if (kret != KERN_SUCCESS) return kret; + + return KERN_SUCCESS; +} + +char * +find_executable(int pid) { + static char pathbuf[PATH_MAX]; + proc_pidpath(pid, pathbuf, PATH_MAX); + return pathbuf; +} + +kern_return_t +get_threads(task_t task, void *slice, int limit) { + kern_return_t kret; + thread_act_array_t list; + mach_msg_type_number_t count; + + kret = task_threads(task, &list, &count); + if (kret != KERN_SUCCESS) { + return kret; + } + + if (count > limit) { + vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); + return -2; + } + + memcpy(slice, (void*)list, count*sizeof(list[0])); + + kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); + if (kret != KERN_SUCCESS) return kret; + + return (kern_return_t)0; +} + +int +thread_count(task_t task) { + kern_return_t kret; + thread_act_array_t list; + mach_msg_type_number_t count; + + kret = task_threads(task, &list, &count); + if (kret != KERN_SUCCESS) return -1; + + kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); + if (kret != KERN_SUCCESS) return -1; + + return count; +} + +mach_port_t +mach_port_wait(mach_port_t port_set, task_t *task, int nonblocking) { + kern_return_t kret; + thread_act_t thread; + NDR_record_t *ndr; + integer_t *data; + union + { + mach_msg_header_t hdr; + char data[256]; + } msg; + mach_msg_option_t opts = MACH_RCV_MSG|MACH_RCV_INTERRUPT; + if (nonblocking) { + opts |= MACH_RCV_TIMEOUT; + } + + // Wait for mach msg. + kret = mach_msg(&msg.hdr, opts, + 0, sizeof(msg.data), port_set, 10, MACH_PORT_NULL); + if (kret == MACH_RCV_INTERRUPTED) return kret; + if (kret != MACH_MSG_SUCCESS) return 0; + + + switch (msg.hdr.msgh_id) { + case 2401: { // Exception + // 2401 is the exception_raise event, defined in: + // http://opensource.apple.com/source/xnu/xnu-2422.1.72/osfmk/mach/exc.defs?txt + // compile this file with mig to get the C version of the description + + mach_msg_body_t *bod = (mach_msg_body_t*)(&msg.hdr + 1); + mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1); + thread = desc[0].name; + *task = desc[1].name; + ndr = (NDR_record_t *)(desc + 2); + data = (integer_t *)(ndr + 1); + + if (thread_suspend(thread) != KERN_SUCCESS) return 0; + // Send our reply back so the kernel knows this exception has been handled. + kret = mach_send_reply(msg.hdr); + if (kret != MACH_MSG_SUCCESS) return 0; + if (data[2] == EXC_SOFT_SIGNAL) { + if (data[3] != SIGTRAP) { + if (thread_resume(thread) != KERN_SUCCESS) return 0; + return mach_port_wait(port_set, task, nonblocking); + } + } + return thread; + } + + case 72: { // Death + // 72 is mach_notify_dead_name, defined in: + // https://opensource.apple.com/source/xnu/xnu-1228.7.58/osfmk/mach/notify.defs?txt + // compile this file with mig to get the C version of the description + ndr = (NDR_record_t *)(&msg.hdr + 1); + *task = *((mach_port_name_t *)(ndr + 1)); + return msg.hdr.msgh_local_port; + } + } + return 0; +} + +kern_return_t +mach_send_reply(mach_msg_header_t hdr) { + mig_reply_error_t reply; + mach_msg_header_t *rh = &reply.Head; + rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr.msgh_bits), 0); + rh->msgh_remote_port = hdr.msgh_remote_port; + rh->msgh_size = (mach_msg_size_t) sizeof(mig_reply_error_t); + rh->msgh_local_port = MACH_PORT_NULL; + rh->msgh_id = hdr.msgh_id + 100; + + reply.NDR = NDR_record; + reply.RetCode = KERN_SUCCESS; + + return mach_msg(&reply.Head, MACH_SEND_MSG|MACH_SEND_INTERRUPT, rh->msgh_size, 0, + MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); +} + +kern_return_t +raise_exception(mach_port_t task, mach_port_t thread, mach_port_t exception_port, exception_type_t exception) { + return exception_raise(exception_port, thread, task, exception, 0, 0); +} + +task_t +get_task_for_pid(int pid) { + task_t task = 0; + mach_port_t self = mach_task_self(); + + task_for_pid(self, pid, &task); + return task; +} + +int +task_is_valid(task_t task) { + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + return task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS; +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.go b/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.go new file mode 100644 index 0000000..2a71300 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.go @@ -0,0 +1,511 @@ +package proc + +// #include "proc_darwin.h" +// #include "threads_darwin.h" +// #include "exec_darwin.h" +// #include +import "C" +import ( + "debug/gosym" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sync" + "unsafe" + + "golang.org/x/debug/macho" + + "github.com/derekparker/delve/pkg/dwarf/frame" + "github.com/derekparker/delve/pkg/dwarf/line" + sys "golang.org/x/sys/unix" +) + +// OSProcessDetails holds Darwin specific information. +type OSProcessDetails struct { + task C.task_t // mach task for the debugged process. + exceptionPort C.mach_port_t // mach port for receiving mach exceptions. + notificationPort C.mach_port_t // mach port for dead name notification (process exit). + initialized bool + + // the main port we use, will return messages from both the + // exception and notification ports. + portSet C.mach_port_t +} + +// Launch creates and begins debugging a new process. Uses a +// custom fork/exec process in order to take advantage of +// PT_SIGEXC on Darwin which will turn Unix signals into +// Mach exceptions. +func Launch(cmd []string, wd string) (*Process, error) { + // check that the argument to Launch is an executable file + if fi, staterr := os.Stat(cmd[0]); staterr == nil && (fi.Mode()&0111) == 0 { + return nil, NotExecutableErr + } + argv0Go, err := filepath.Abs(cmd[0]) + if err != nil { + return nil, err + } + // Make sure the binary exists. + if filepath.Base(cmd[0]) == cmd[0] { + if _, err := exec.LookPath(cmd[0]); err != nil { + return nil, err + } + } + if _, err := os.Stat(argv0Go); err != nil { + return nil, err + } + + argv0 := C.CString(argv0Go) + argvSlice := make([]*C.char, 0, len(cmd)+1) + for _, arg := range cmd { + argvSlice = append(argvSlice, C.CString(arg)) + } + // argv array must be null terminated. + argvSlice = append(argvSlice, nil) + + dbp := New(0) + var pid int + dbp.execPtraceFunc(func() { + ret := C.fork_exec(argv0, &argvSlice[0], C.int(len(argvSlice)), + C.CString(wd), + &dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort, + &dbp.os.notificationPort) + pid = int(ret) + }) + if pid <= 0 { + return nil, fmt.Errorf("could not fork/exec") + } + dbp.pid = pid + for i := range argvSlice { + C.free(unsafe.Pointer(argvSlice[i])) + } + + // Initialize enough of the Process state so that we can use resume and + // trapWait to wait until the child process calls execve. + + for { + err = dbp.updateThreadListForTask(C.get_task_for_pid(C.int(dbp.pid))) + if err == nil { + break + } + if err != couldNotGetThreadCount && err != couldNotGetThreadList { + return nil, err + } + } + + if err := dbp.resume(); err != nil { + return nil, err + } + + dbp.allGCache = nil + for _, th := range dbp.threads { + th.clearBreakpointState() + } + + trapthread, err := dbp.trapWait(-1) + if err != nil { + return nil, err + } + if err := dbp.Halt(); err != nil { + return nil, dbp.exitGuard(err) + } + + _, err = dbp.waitForStop() + if err != nil { + return nil, err + } + + dbp.os.initialized = true + dbp, err = initializeDebugProcess(dbp, argv0Go, false) + if err != nil { + return nil, err + } + + if err := dbp.SwitchThread(trapthread.ID); err != nil { + return nil, err + } + + return dbp, err +} + +// Attach to an existing process with the given PID. +func Attach(pid int) (*Process, error) { + dbp := New(pid) + + kret := C.acquire_mach_task(C.int(pid), + &dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort, + &dbp.os.notificationPort) + + if kret != C.KERN_SUCCESS { + return nil, fmt.Errorf("could not attach to %d", pid) + } + + dbp.os.initialized = true + + return initializeDebugProcess(dbp, "", true) +} + +// Kill kills the process. +func (dbp *Process) Kill() (err error) { + if dbp.exited { + return nil + } + err = sys.Kill(-dbp.pid, sys.SIGKILL) + if err != nil { + return errors.New("could not deliver signal: " + err.Error()) + } + for port := range dbp.threads { + if C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS { + return errors.New("could not resume task") + } + } + for { + var task C.task_t + port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0)) + if port == dbp.os.notificationPort { + break + } + } + dbp.postExit() + return +} + +func (dbp *Process) requestManualStop() (err error) { + var ( + task = C.mach_port_t(dbp.os.task) + thread = C.mach_port_t(dbp.currentThread.os.threadAct) + exceptionPort = C.mach_port_t(dbp.os.exceptionPort) + ) + kret := C.raise_exception(task, thread, exceptionPort, C.EXC_BREAKPOINT) + if kret != C.KERN_SUCCESS { + return fmt.Errorf("could not raise mach exception") + } + return nil +} + +var couldNotGetThreadCount = errors.New("could not get thread count") +var couldNotGetThreadList = errors.New("could not get thread list") + +func (dbp *Process) updateThreadList() error { + return dbp.updateThreadListForTask(dbp.os.task) +} + +func (dbp *Process) updateThreadListForTask(task C.task_t) error { + var ( + err error + kret C.kern_return_t + count C.int + list []uint32 + ) + + for { + count = C.thread_count(task) + if count == -1 { + return couldNotGetThreadCount + } + list = make([]uint32, count) + + // TODO(dp) might be better to malloc mem in C and then free it here + // instead of getting count above and passing in a slice + kret = C.get_threads(task, unsafe.Pointer(&list[0]), count) + if kret != -2 { + break + } + } + if kret != C.KERN_SUCCESS { + return couldNotGetThreadList + } + + for _, thread := range dbp.threads { + thread.os.exists = false + } + + for _, port := range list { + thread, ok := dbp.threads[int(port)] + if !ok { + thread, err = dbp.addThread(int(port), false) + if err != nil { + return err + } + } + thread.os.exists = true + } + + for threadID, thread := range dbp.threads { + if !thread.os.exists { + delete(dbp.threads, threadID) + } + } + + return nil +} + +func (dbp *Process) addThread(port int, attach bool) (*Thread, error) { + if thread, ok := dbp.threads[port]; ok { + return thread, nil + } + thread := &Thread{ + ID: port, + dbp: dbp, + os: new(OSSpecificDetails), + } + dbp.threads[port] = thread + thread.os.threadAct = C.thread_act_t(port) + if dbp.currentThread == nil { + dbp.SwitchThread(thread.ID) + } + return thread, nil +} + +func (dbp *Process) parseDebugFrame(exe *macho.File, wg *sync.WaitGroup) { + defer wg.Done() + + debugFrameSec := exe.Section("__debug_frame") + debugInfoSec := exe.Section("__debug_info") + + if debugFrameSec != nil && debugInfoSec != nil { + debugFrame, err := exe.Section("__debug_frame").Data() + if err != nil { + fmt.Println("could not get __debug_frame section", err) + os.Exit(1) + } + dat, err := debugInfoSec.Data() + if err != nil { + fmt.Println("could not get .debug_info section", err) + os.Exit(1) + } + dbp.frameEntries = frame.Parse(debugFrame, frame.DwarfEndian(dat)) + } else { + fmt.Println("could not find __debug_frame section in binary") + os.Exit(1) + } +} + +func (dbp *Process) obtainGoSymbols(exe *macho.File, wg *sync.WaitGroup) { + defer wg.Done() + + var ( + symdat []byte + pclndat []byte + err error + ) + + if sec := exe.Section("__gosymtab"); sec != nil { + symdat, err = sec.Data() + if err != nil { + fmt.Println("could not get .gosymtab section", err) + os.Exit(1) + } + } + + if sec := exe.Section("__gopclntab"); sec != nil { + pclndat, err = sec.Data() + if err != nil { + fmt.Println("could not get .gopclntab section", err) + os.Exit(1) + } + } + + pcln := gosym.NewLineTable(pclndat, exe.Section("__text").Addr) + tab, err := gosym.NewTable(symdat, pcln) + if err != nil { + fmt.Println("could not get initialize line table", err) + os.Exit(1) + } + + dbp.goSymTable = tab +} + +func (dbp *Process) parseDebugLineInfo(exe *macho.File, wg *sync.WaitGroup) { + defer wg.Done() + + if sec := exe.Section("__debug_line"); sec != nil { + debugLine, err := exe.Section("__debug_line").Data() + if err != nil { + fmt.Println("could not get __debug_line section", err) + os.Exit(1) + } + dbp.lineInfo = line.Parse(debugLine) + } else { + fmt.Println("could not find __debug_line section in binary") + os.Exit(1) + } +} + +var UnsupportedArchErr = errors.New("unsupported architecture - only darwin/amd64 is supported") + +func (dbp *Process) findExecutable(path string) (*macho.File, string, error) { + if path == "" { + path = C.GoString(C.find_executable(C.int(dbp.pid))) + } + exe, err := macho.Open(path) + if err != nil { + return nil, path, err + } + if exe.Cpu != macho.CpuAmd64 { + return nil, path, UnsupportedArchErr + } + dbp.dwarf, err = exe.DWARF() + if err != nil { + return nil, path, err + } + return exe, path, nil +} + +func (dbp *Process) trapWait(pid int) (*Thread, error) { + for { + task := dbp.os.task + port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0)) + + switch port { + case dbp.os.notificationPort: + // on macOS >= 10.12.1 the task_t changes after an execve, we could + // receive the notification for the death of the pre-execve task_t, + // this could also happen *before* we are notified that our task_t has + // changed. + if dbp.os.task != task { + continue + } + if !dbp.os.initialized { + if pidtask := C.get_task_for_pid(C.int(dbp.pid)); pidtask != 0 && dbp.os.task != pidtask { + continue + } + } + _, status, err := dbp.wait(dbp.pid, 0) + if err != nil { + return nil, err + } + dbp.postExit() + return nil, ProcessExitedError{Pid: dbp.pid, Status: status.ExitStatus()} + + case C.MACH_RCV_INTERRUPTED: + if !dbp.halt { + // Call trapWait again, it seems + // MACH_RCV_INTERRUPTED is emitted before + // process natural death _sometimes_. + continue + } + return nil, nil + + case 0: + return nil, fmt.Errorf("error while waiting for task") + } + + // In macOS 10.12.1 if we received a notification for a task other than + // the inferior's task and the inferior's task is no longer valid, this + // means inferior called execve and its task_t changed. + if dbp.os.task != task && C.task_is_valid(dbp.os.task) == 0 { + dbp.os.task = task + kret := C.reset_exception_ports(dbp.os.task, &dbp.os.exceptionPort, &dbp.os.notificationPort) + if kret != C.KERN_SUCCESS { + return nil, fmt.Errorf("could not follow task across exec: %d\n", kret) + } + } + + // Since we cannot be notified of new threads on OS X + // this is as good a time as any to check for them. + dbp.updateThreadList() + th, ok := dbp.threads[int(port)] + if !ok { + if dbp.halt { + dbp.halt = false + return th, nil + } + if dbp.firstStart || th.singleStepping { + dbp.firstStart = false + return th, nil + } + if err := th.Continue(); err != nil { + return nil, err + } + continue + } + return th, nil + } +} + +func (dbp *Process) waitForStop() ([]int, error) { + ports := make([]int, 0, len(dbp.threads)) + count := 0 + for { + var task C.task_t + port := C.mach_port_wait(dbp.os.portSet, &task, C.int(1)) + if port != 0 && port != dbp.os.notificationPort && port != C.MACH_RCV_INTERRUPTED { + count = 0 + ports = append(ports, int(port)) + } else { + n := C.num_running_threads(dbp.os.task) + if n == 0 { + return ports, nil + } else if n < 0 { + return nil, fmt.Errorf("error waiting for thread stop %d", n) + } else if count > 16 { + return nil, fmt.Errorf("could not stop process %d", n) + } + } + } +} + +func (dbp *Process) setCurrentBreakpoints(trapthread *Thread) error { + ports, err := dbp.waitForStop() + if err != nil { + return err + } + trapthread.SetCurrentBreakpoint() + for _, port := range ports { + if th, ok := dbp.threads[port]; ok { + err := th.SetCurrentBreakpoint() + if err != nil { + return err + } + } + } + return nil +} + +func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) { + wg.Done() +} + +func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { + var status sys.WaitStatus + wpid, err := sys.Wait4(pid, &status, options, nil) + return wpid, &status, err +} + +func killProcess(pid int) error { + return sys.Kill(pid, sys.SIGINT) +} + +func (dbp *Process) exitGuard(err error) error { + if err != ErrContinueThread { + return err + } + _, status, werr := dbp.wait(dbp.pid, sys.WNOHANG) + if werr == nil && status.Exited() { + dbp.postExit() + return ProcessExitedError{Pid: dbp.pid, Status: status.ExitStatus()} + } + return err +} + +func (dbp *Process) resume() error { + // all threads stopped over a breakpoint are made to step over it + for _, thread := range dbp.threads { + if thread.CurrentBreakpoint != nil { + if err := thread.StepInstruction(); err != nil { + return err + } + thread.CurrentBreakpoint = nil + } + } + // everything is resumed + for _, thread := range dbp.threads { + if err := thread.resume(); err != nil { + return dbp.exitGuard(err) + } + } + return nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.h b/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.h new file mode 100644 index 0000000..022ab14 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.h @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include "mach_exc.h" +#include "exc.h" + +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +boolean_t exc_server( + mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +boolean_t mach_exc_server( + mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + +kern_return_t +acquire_mach_task(int, task_t*, mach_port_t*, mach_port_t*, mach_port_t*); + +char * +find_executable(int pid); + +kern_return_t +get_threads(task_t task, void *data,int limit); + +int +thread_count(task_t task); + +mach_port_t +mach_port_wait(mach_port_t, task_t*, int); + +kern_return_t +mach_send_reply(mach_msg_header_t); + +kern_return_t +raise_exception(mach_port_t, mach_port_t, mach_port_t, exception_type_t); + +kern_return_t +reset_exception_ports(task_t task, mach_port_t *exception_port, mach_port_t *notification_port); + +task_t +get_task_for_pid(int pid); + +int +task_is_valid(task_t task); diff --git a/vendor/github.com/derekparker/delve/pkg/proc/proc_linux.go b/vendor/github.com/derekparker/delve/pkg/proc/proc_linux.go new file mode 100644 index 0000000..4969f0f --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/proc_linux.go @@ -0,0 +1,489 @@ +package proc + +import ( + "bytes" + "debug/gosym" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "sync" + "syscall" + "time" + + sys "golang.org/x/sys/unix" + + "github.com/derekparker/delve/pkg/dwarf/frame" + "github.com/derekparker/delve/pkg/dwarf/line" + "golang.org/x/debug/elf" +) + +// Process statuses +const ( + StatusSleeping = 'S' + StatusRunning = 'R' + StatusTraceStop = 't' + StatusZombie = 'Z' + + // Kernel 2.6 has TraceStop as T + // TODO(derekparker) Since this means something different based on the + // version of the kernel ('T' is job control stop on modern 3.x+ kernels) we + // may want to differentiate at some point. + StatusTraceStopT = 'T' +) + +// OSProcessDetails contains Linux specific +// process details. +type OSProcessDetails struct { + comm string +} + +// Launch creates and begins debugging a new process. First entry in +// `cmd` is the program to run, and then rest are the arguments +// to be supplied to that process. `wd` is working directory of the program. +func Launch(cmd []string, wd string) (*Process, error) { + var ( + proc *exec.Cmd + err error + ) + // check that the argument to Launch is an executable file + if fi, staterr := os.Stat(cmd[0]); staterr == nil && (fi.Mode()&0111) == 0 { + return nil, NotExecutableErr + } + dbp := New(0) + dbp.execPtraceFunc(func() { + proc = exec.Command(cmd[0]) + proc.Args = cmd + proc.Stdout = os.Stdout + proc.Stderr = os.Stderr + proc.SysProcAttr = &syscall.SysProcAttr{Ptrace: true, Setpgid: true} + if wd != "" { + proc.Dir = wd + } + err = proc.Start() + }) + if err != nil { + return nil, err + } + dbp.pid = proc.Process.Pid + _, _, err = dbp.wait(proc.Process.Pid, 0) + if err != nil { + return nil, fmt.Errorf("waiting for target execve failed: %s", err) + } + return initializeDebugProcess(dbp, proc.Path, false) +} + +// Attach to an existing process with the given PID. +func Attach(pid int) (*Process, error) { + return initializeDebugProcess(New(pid), "", true) +} + +// Kill kills the target process. +func (dbp *Process) Kill() (err error) { + if dbp.exited { + return nil + } + if !dbp.threads[dbp.pid].Stopped() { + return errors.New("process must be stopped in order to kill it") + } + if err = sys.Kill(-dbp.pid, sys.SIGKILL); err != nil { + return errors.New("could not deliver signal " + err.Error()) + } + if _, _, err = dbp.wait(dbp.pid, 0); err != nil { + return + } + dbp.postExit() + return +} + +func (dbp *Process) requestManualStop() (err error) { + return sys.Kill(dbp.pid, sys.SIGTRAP) +} + +// Attach to a newly created thread, and store that thread in our list of +// known threads. +func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) { + if thread, ok := dbp.threads[tid]; ok { + return thread, nil + } + + var err error + if attach { + dbp.execPtraceFunc(func() { err = sys.PtraceAttach(tid) }) + if err != nil && err != sys.EPERM { + // Do not return err if err == EPERM, + // we may already be tracing this thread due to + // PTRACE_O_TRACECLONE. We will surely blow up later + // if we truly don't have permissions. + return nil, fmt.Errorf("could not attach to new thread %d %s", tid, err) + } + pid, status, err := dbp.wait(tid, 0) + if err != nil { + return nil, err + } + if status.Exited() { + return nil, fmt.Errorf("thread already exited %d", pid) + } + } + + dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) }) + if err == syscall.ESRCH { + if _, _, err = dbp.wait(tid, 0); err != nil { + return nil, fmt.Errorf("error while waiting after adding thread: %d %s", tid, err) + } + dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) }) + if err == syscall.ESRCH { + return nil, err + } + if err != nil { + return nil, fmt.Errorf("could not set options for new traced thread %d %s", tid, err) + } + } + + dbp.threads[tid] = &Thread{ + ID: tid, + dbp: dbp, + os: new(OSSpecificDetails), + } + if dbp.currentThread == nil { + dbp.SwitchThread(tid) + } + return dbp.threads[tid], nil +} + +func (dbp *Process) updateThreadList() error { + tids, _ := filepath.Glob(fmt.Sprintf("/proc/%d/task/*", dbp.pid)) + for _, tidpath := range tids { + tidstr := filepath.Base(tidpath) + tid, err := strconv.Atoi(tidstr) + if err != nil { + return err + } + if _, err := dbp.addThread(tid, tid != dbp.pid); err != nil { + return err + } + } + return nil +} + +var UnsupportedArchErr = errors.New("unsupported architecture - only linux/amd64 is supported") + +func (dbp *Process) findExecutable(path string) (*elf.File, string, error) { + if path == "" { + path = fmt.Sprintf("/proc/%d/exe", dbp.pid) + } + f, err := os.OpenFile(path, 0, os.ModePerm) + if err != nil { + return nil, path, err + } + elfFile, err := elf.NewFile(f) + if err != nil { + return nil, path, err + } + if elfFile.Machine != elf.EM_X86_64 { + return nil, path, UnsupportedArchErr + } + dbp.dwarf, err = elfFile.DWARF() + if err != nil { + return nil, path, err + } + return elfFile, path, nil +} + +func (dbp *Process) parseDebugFrame(exe *elf.File, wg *sync.WaitGroup) { + defer wg.Done() + + debugFrameSec := exe.Section(".debug_frame") + debugInfoSec := exe.Section(".debug_info") + + if debugFrameSec != nil && debugInfoSec != nil { + debugFrame, err := exe.Section(".debug_frame").Data() + if err != nil { + fmt.Println("could not get .debug_frame section", err) + os.Exit(1) + } + dat, err := debugInfoSec.Data() + if err != nil { + fmt.Println("could not get .debug_info section", err) + os.Exit(1) + } + dbp.frameEntries = frame.Parse(debugFrame, frame.DwarfEndian(dat)) + } else { + fmt.Println("could not find .debug_frame section in binary") + os.Exit(1) + } +} + +func (dbp *Process) obtainGoSymbols(exe *elf.File, wg *sync.WaitGroup) { + defer wg.Done() + + var ( + symdat []byte + pclndat []byte + err error + ) + + if sec := exe.Section(".gosymtab"); sec != nil { + symdat, err = sec.Data() + if err != nil { + fmt.Println("could not get .gosymtab section", err) + os.Exit(1) + } + } + + if sec := exe.Section(".gopclntab"); sec != nil { + pclndat, err = sec.Data() + if err != nil { + fmt.Println("could not get .gopclntab section", err) + os.Exit(1) + } + } + + pcln := gosym.NewLineTable(pclndat, exe.Section(".text").Addr) + tab, err := gosym.NewTable(symdat, pcln) + if err != nil { + fmt.Println("could not get initialize line table", err) + os.Exit(1) + } + + dbp.goSymTable = tab +} + +func (dbp *Process) parseDebugLineInfo(exe *elf.File, wg *sync.WaitGroup) { + defer wg.Done() + + if sec := exe.Section(".debug_line"); sec != nil { + debugLine, err := exe.Section(".debug_line").Data() + if err != nil { + fmt.Println("could not get .debug_line section", err) + os.Exit(1) + } + dbp.lineInfo = line.Parse(debugLine) + } else { + fmt.Println("could not find .debug_line section in binary") + os.Exit(1) + } +} + +func (dbp *Process) trapWait(pid int) (*Thread, error) { + for { + wpid, status, err := dbp.wait(pid, 0) + if err != nil { + return nil, fmt.Errorf("wait err %s %d", err, pid) + } + if wpid == 0 { + continue + } + th, ok := dbp.threads[wpid] + if ok { + th.Status = (*WaitStatus)(status) + } + if status.Exited() { + if wpid == dbp.pid { + dbp.postExit() + return nil, ProcessExitedError{Pid: wpid, Status: status.ExitStatus()} + } + delete(dbp.threads, wpid) + continue + } + if status.StopSignal() == sys.SIGTRAP && status.TrapCause() == sys.PTRACE_EVENT_CLONE { + // A traced thread has cloned a new thread, grab the pid and + // add it to our list of traced threads. + var cloned uint + dbp.execPtraceFunc(func() { cloned, err = sys.PtraceGetEventMsg(wpid) }) + if err != nil { + if err == sys.ESRCH { + // thread died while we were adding it + continue + } + return nil, fmt.Errorf("could not get event message: %s", err) + } + th, err = dbp.addThread(int(cloned), false) + if err != nil { + if err == sys.ESRCH { + // thread died while we were adding it + continue + } + return nil, err + } + if err = th.Continue(); err != nil { + if err == sys.ESRCH { + // thread died while we were adding it + delete(dbp.threads, th.ID) + continue + } + return nil, fmt.Errorf("could not continue new thread %d %s", cloned, err) + } + if err = dbp.threads[int(wpid)].Continue(); err != nil { + if err != sys.ESRCH { + return nil, fmt.Errorf("could not continue existing thread %d %s", wpid, err) + } + } + continue + } + if th == nil { + // Sometimes we get an unknown thread, ignore it? + continue + } + if status.StopSignal() == sys.SIGTRAP && dbp.halt { + th.running = false + dbp.halt = false + return th, nil + } + if status.StopSignal() == sys.SIGTRAP { + th.running = false + return th, nil + } + if th != nil { + // TODO(dp) alert user about unexpected signals here. + if err := th.resumeWithSig(int(status.StopSignal())); err != nil { + if err == sys.ESRCH { + return nil, ProcessExitedError{Pid: dbp.pid} + } + return nil, err + } + } + } +} + +func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) { + defer wg.Done() + + comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.pid)) + if err == nil { + // removes newline character + comm = bytes.TrimSuffix(comm, []byte("\n")) + } + + if comm == nil || len(comm) <= 0 { + stat, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", dbp.pid)) + if err != nil { + fmt.Printf("Could not read proc stat: %v\n", err) + os.Exit(1) + } + expr := fmt.Sprintf("%d\\s*\\((.*)\\)", dbp.pid) + rexp, err := regexp.Compile(expr) + if err != nil { + fmt.Printf("Regexp compile error: %v\n", err) + os.Exit(1) + } + match := rexp.FindSubmatch(stat) + if match == nil { + fmt.Printf("No match found using regexp '%s' in /proc/%d/stat\n", expr, dbp.pid) + os.Exit(1) + } + comm = match[1] + } + dbp.os.comm = strings.Replace(string(comm), "%", "%%", -1) +} + +func status(pid int, comm string) rune { + f, err := os.Open(fmt.Sprintf("/proc/%d/stat", pid)) + if err != nil { + return '\000' + } + defer f.Close() + + var ( + p int + state rune + ) + + // The second field of /proc/pid/stat is the name of the task in parenthesis. + // The name of the task is the base name of the executable for this process limited to TASK_COMM_LEN characters + // Since both parenthesis and spaces can appear inside the name of the task and no escaping happens we need to read the name of the executable first + // See: include/linux/sched.c:315 and include/linux/sched.c:1510 + fmt.Fscanf(f, "%d ("+comm+") %c", &p, &state) + return state +} + +// waitFast is like wait but does not handle process-exit correctly +func (dbp *Process) waitFast(pid int) (int, *sys.WaitStatus, error) { + var s sys.WaitStatus + wpid, err := sys.Wait4(pid, &s, sys.WALL, nil) + return wpid, &s, err +} + +func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { + var s sys.WaitStatus + if (pid != dbp.pid) || (options != 0) { + wpid, err := sys.Wait4(pid, &s, sys.WALL|options, nil) + return wpid, &s, err + } + // If we call wait4/waitpid on a thread that is the leader of its group, + // with options == 0, while ptracing and the thread leader has exited leaving + // zombies of its own then waitpid hangs forever this is apparently intended + // behaviour in the linux kernel because it's just so convenient. + // Therefore we call wait4 in a loop with WNOHANG, sleeping a while between + // calls and exiting when either wait4 succeeds or we find out that the thread + // has become a zombie. + // References: + // https://sourceware.org/bugzilla/show_bug.cgi?id=12702 + // https://sourceware.org/bugzilla/show_bug.cgi?id=10095 + // https://sourceware.org/bugzilla/attachment.cgi?id=5685 + for { + wpid, err := sys.Wait4(pid, &s, sys.WNOHANG|sys.WALL|options, nil) + if err != nil { + return 0, nil, err + } + if wpid != 0 { + return wpid, &s, err + } + if status(pid, dbp.os.comm) == StatusZombie { + return pid, nil, nil + } + time.Sleep(200 * time.Millisecond) + } +} + +func (dbp *Process) setCurrentBreakpoints(trapthread *Thread) error { + for _, th := range dbp.threads { + if th.CurrentBreakpoint == nil { + err := th.SetCurrentBreakpoint() + if err != nil { + return err + } + } + } + return nil +} + +func (dbp *Process) exitGuard(err error) error { + if err != sys.ESRCH { + return err + } + if status(dbp.pid, dbp.os.comm) == StatusZombie { + _, err := dbp.trapWait(-1) + return err + } + + return err +} + +func (dbp *Process) resume() error { + // all threads stopped over a breakpoint are made to step over it + for _, thread := range dbp.threads { + if thread.CurrentBreakpoint != nil { + if err := thread.StepInstruction(); err != nil { + return err + } + thread.CurrentBreakpoint = nil + } + } + // everything is resumed + for _, thread := range dbp.threads { + if err := thread.resume(); err != nil && err != sys.ESRCH { + return err + } + } + return nil +} + +func killProcess(pid int) error { + return sys.Kill(pid, sys.SIGINT) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/proc_windows.go b/vendor/github.com/derekparker/delve/pkg/proc/proc_windows.go new file mode 100644 index 0000000..d3b7773 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/proc_windows.go @@ -0,0 +1,672 @@ +package proc + +import ( + "debug/gosym" + "debug/pe" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sync" + "syscall" + "unsafe" + + sys "golang.org/x/sys/windows" + + "github.com/derekparker/delve/pkg/dwarf/frame" + "github.com/derekparker/delve/pkg/dwarf/line" + "golang.org/x/debug/dwarf" +) + +// OSProcessDetails holds Windows specific information. +type OSProcessDetails struct { + hProcess syscall.Handle + breakThread int +} + +// Launch creates and begins debugging a new process. +func Launch(cmd []string, wd string) (*Process, error) { + argv0Go, err := filepath.Abs(cmd[0]) + if err != nil { + return nil, err + } + + // Make sure the binary exists and is an executable file + if filepath.Base(cmd[0]) == cmd[0] { + if _, err := exec.LookPath(cmd[0]); err != nil { + return nil, err + } + } + + peFile, err := openExecutablePath(argv0Go) + if err != nil { + return nil, NotExecutableErr + } + peFile.Close() + + // Duplicate the stdin/stdout/stderr handles + files := []uintptr{uintptr(syscall.Stdin), uintptr(syscall.Stdout), uintptr(syscall.Stderr)} + p, _ := syscall.GetCurrentProcess() + fd := make([]syscall.Handle, len(files)) + for i := range files { + err := syscall.DuplicateHandle(p, syscall.Handle(files[i]), p, &fd[i], 0, true, syscall.DUPLICATE_SAME_ACCESS) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(syscall.Handle(fd[i])) + } + + argv0, err := syscall.UTF16PtrFromString(argv0Go) + if err != nil { + return nil, err + } + + // create suitable command line for CreateProcess + // see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L326 + // adapted from standard library makeCmdLine + // see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L86 + var cmdLineGo string + if len(cmd) >= 1 { + for _, v := range cmd { + if cmdLineGo != "" { + cmdLineGo += " " + } + cmdLineGo += syscall.EscapeArg(v) + } + } + + var cmdLine *uint16 + if cmdLineGo != "" { + if cmdLine, err = syscall.UTF16PtrFromString(cmdLineGo); err != nil { + return nil, err + } + } + + var workingDir *uint16 + if wd != "" { + if workingDir, err = syscall.UTF16PtrFromString(wd); err != nil { + return nil, err + } + } + + // Initialize the startup info and create process + si := new(sys.StartupInfo) + si.Cb = uint32(unsafe.Sizeof(*si)) + si.Flags = syscall.STARTF_USESTDHANDLES + si.StdInput = sys.Handle(fd[0]) + si.StdOutput = sys.Handle(fd[1]) + si.StdErr = sys.Handle(fd[2]) + pi := new(sys.ProcessInformation) + + dbp := New(0) + dbp.execPtraceFunc(func() { + if wd == "" { + err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, _DEBUG_ONLY_THIS_PROCESS, nil, nil, si, pi) + } else { + err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, _DEBUG_ONLY_THIS_PROCESS, nil, workingDir, si, pi) + } + }) + if err != nil { + return nil, err + } + sys.CloseHandle(sys.Handle(pi.Process)) + sys.CloseHandle(sys.Handle(pi.Thread)) + + dbp.pid = int(pi.ProcessId) + + return newDebugProcess(dbp, argv0Go) +} + +// newDebugProcess prepares process pid for debugging. +func newDebugProcess(dbp *Process, exepath string) (*Process, error) { + // It should not actually be possible for the + // call to waitForDebugEvent to fail, since Windows + // will always fire a CREATE_PROCESS_DEBUG_EVENT event + // immediately after launching under DEBUG_ONLY_THIS_PROCESS. + // Attaching with DebugActiveProcess has similar effect. + var err error + var tid, exitCode int + dbp.execPtraceFunc(func() { + tid, exitCode, err = dbp.waitForDebugEvent(waitBlocking) + }) + if err != nil { + return nil, err + } + if tid == 0 { + dbp.postExit() + return nil, ProcessExitedError{Pid: dbp.pid, Status: exitCode} + } + // Suspend all threads so that the call to _ContinueDebugEvent will + // not resume the target. + for _, thread := range dbp.threads { + _, err := _SuspendThread(thread.os.hThread) + if err != nil { + return nil, err + } + } + + dbp.execPtraceFunc(func() { + err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE) + }) + if err != nil { + return nil, err + } + + return initializeDebugProcess(dbp, exepath, false) +} + +// findExePath searches for process pid, and returns its executable path. +func findExePath(pid int) (string, error) { + // Original code suggested different approach (see below). + // Maybe it could be useful in the future. + // + // Find executable path from PID/handle on Windows: + // https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx + + p, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid)) + if err != nil { + return "", err + } + defer syscall.CloseHandle(p) + + n := uint32(128) + for { + buf := make([]uint16, int(n)) + err = _QueryFullProcessImageName(p, 0, &buf[0], &n) + switch err { + case syscall.ERROR_INSUFFICIENT_BUFFER: + // try bigger buffer + n *= 2 + // but stop if it gets too big + if n > 10000 { + return "", err + } + case nil: + return syscall.UTF16ToString(buf[:n]), nil + default: + return "", err + } + } +} + +// Attach to an existing process with the given PID. +func Attach(pid int) (*Process, error) { + // TODO: Probably should have SeDebugPrivilege before starting here. + err := _DebugActiveProcess(uint32(pid)) + if err != nil { + return nil, err + } + exepath, err := findExePath(pid) + if err != nil { + return nil, err + } + return newDebugProcess(New(pid), exepath) +} + +// Kill kills the process. +func (dbp *Process) Kill() error { + if dbp.exited { + return nil + } + if !dbp.threads[dbp.pid].Stopped() { + return errors.New("process must be stopped in order to kill it") + } + // TODO: Should not have to ignore failures here, + // but some tests appear to Kill twice causing + // this to fail on second attempt. + _ = syscall.TerminateProcess(dbp.os.hProcess, 1) + dbp.exited = true + return nil +} + +func (dbp *Process) requestManualStop() error { + return _DebugBreakProcess(dbp.os.hProcess) +} + +func (dbp *Process) updateThreadList() error { + // We ignore this request since threads are being + // tracked as they are created/killed in waitForDebugEvent. + return nil +} + +func (dbp *Process) addThread(hThread syscall.Handle, threadID int, attach, suspendNewThreads bool) (*Thread, error) { + if thread, ok := dbp.threads[threadID]; ok { + return thread, nil + } + thread := &Thread{ + ID: threadID, + dbp: dbp, + os: new(OSSpecificDetails), + } + thread.os.hThread = hThread + dbp.threads[threadID] = thread + if dbp.currentThread == nil { + dbp.SwitchThread(thread.ID) + } + if suspendNewThreads { + _, err := _SuspendThread(thread.os.hThread) + if err != nil { + return nil, err + } + } + return thread, nil +} + +func (dbp *Process) parseDebugFrame(exe *pe.File, wg *sync.WaitGroup) { + defer wg.Done() + + debugFrameSec := exe.Section(".debug_frame") + debugInfoSec := exe.Section(".debug_info") + + if debugFrameSec != nil && debugInfoSec != nil { + debugFrame, err := debugFrameSec.Data() + if err != nil && uint32(len(debugFrame)) < debugFrameSec.Size { + fmt.Println("could not get .debug_frame section", err) + os.Exit(1) + } + if 0 < debugFrameSec.VirtualSize && debugFrameSec.VirtualSize < debugFrameSec.Size { + debugFrame = debugFrame[:debugFrameSec.VirtualSize] + } + dat, err := debugInfoSec.Data() + if err != nil { + fmt.Println("could not get .debug_info section", err) + os.Exit(1) + } + dbp.frameEntries = frame.Parse(debugFrame, frame.DwarfEndian(dat)) + } else { + fmt.Println("could not find .debug_frame section in binary") + os.Exit(1) + } +} + +// Borrowed from https://golang.org/src/cmd/internal/objfile/pe.go +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) +} + +// Borrowed from https://golang.org/src/cmd/internal/objfile/pe.go +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 +} + +// Borrowed from https://golang.org/src/cmd/internal/objfile/pe.go +func pcln(exe *pe.File) (textStart uint64, symtab, pclntab []byte, err error) { + var imageBase uint64 + switch oh := exe.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 := exe.Section(".text"); sect != nil { + textStart = imageBase + uint64(sect.VirtualAddress) + } + if pclntab, err = loadPETable(exe, "runtime.pclntab", "runtime.epclntab"); err != nil { + // We didn't find the symbols, so look for the names used in 1.3 and earlier. + // TODO: Remove code looking for the old symbols when we no longer care about 1.3. + var err2 error + if pclntab, err2 = loadPETable(exe, "pclntab", "epclntab"); err2 != nil { + return 0, nil, nil, err + } + } + if symtab, err = loadPETable(exe, "runtime.symtab", "runtime.esymtab"); err != nil { + // Same as above. + var err2 error + if symtab, err2 = loadPETable(exe, "symtab", "esymtab"); err2 != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil +} + +func (dbp *Process) obtainGoSymbols(exe *pe.File, wg *sync.WaitGroup) { + defer wg.Done() + + _, symdat, pclndat, err := pcln(exe) + if err != nil { + fmt.Println("could not get Go symbols", err) + os.Exit(1) + } + + pcln := gosym.NewLineTable(pclndat, uint64(exe.Section(".text").Offset)) + tab, err := gosym.NewTable(symdat, pcln) + if err != nil { + fmt.Println("could not get initialize line table", err) + os.Exit(1) + } + + dbp.goSymTable = tab +} + +func (dbp *Process) parseDebugLineInfo(exe *pe.File, wg *sync.WaitGroup) { + defer wg.Done() + + if sec := exe.Section(".debug_line"); sec != nil { + debugLine, err := sec.Data() + if err != nil && uint32(len(debugLine)) < sec.Size { + fmt.Println("could not get .debug_line section", err) + os.Exit(1) + } + if 0 < sec.VirtualSize && sec.VirtualSize < sec.Size { + debugLine = debugLine[:sec.VirtualSize] + } + dbp.lineInfo = line.Parse(debugLine) + } else { + fmt.Println("could not find .debug_line section in binary") + os.Exit(1) + } +} + +var UnsupportedArchErr = errors.New("unsupported architecture of windows/386 - only windows/amd64 is supported") + +func (dbp *Process) findExecutable(path string) (*pe.File, string, error) { + peFile, err := openExecutablePath(path) + if err != nil { + return nil, path, err + } + if peFile.Machine != pe.IMAGE_FILE_MACHINE_AMD64 { + return nil, path, UnsupportedArchErr + } + dbp.dwarf, err = dwarfFromPE(peFile) + if err != nil { + return nil, path, err + } + return peFile, path, nil +} + +func openExecutablePath(path string) (*pe.File, error) { + f, err := os.OpenFile(path, 0, os.ModePerm) + if err != nil { + return nil, err + } + return pe.NewFile(f) +} + +// Adapted from src/debug/pe/file.go: pe.(*File).DWARF() +func dwarfFromPE(f *pe.File) (*dwarf.Data, error) { + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var names = [...]string{"abbrev", "info", "line", "str"} + var dat [len(names)][]byte + for i, name := range names { + name = ".debug_" + name + s := f.Section(name) + if s == nil { + continue + } + b, err := s.Data() + if err != nil && uint32(len(b)) < s.Size { + return nil, err + } + if 0 < s.VirtualSize && s.VirtualSize < s.Size { + b = b[:s.VirtualSize] + } + dat[i] = b + } + + abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3] + return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str) +} + +type waitForDebugEventFlags int + +const ( + waitBlocking waitForDebugEventFlags = 1 << iota + waitSuspendNewThreads +) + +func (dbp *Process) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, exitCode int, err error) { + var debugEvent _DEBUG_EVENT + shouldExit := false + for { + continueStatus := uint32(_DBG_CONTINUE) + var milliseconds uint32 = 0 + if flags&waitBlocking != 0 { + milliseconds = syscall.INFINITE + } + // Wait for a debug event... + err := _WaitForDebugEvent(&debugEvent, milliseconds) + if err != nil { + return 0, 0, err + } + + // ... handle each event kind ... + unionPtr := unsafe.Pointer(&debugEvent.U[0]) + switch debugEvent.DebugEventCode { + case _CREATE_PROCESS_DEBUG_EVENT: + debugInfo := (*_CREATE_PROCESS_DEBUG_INFO)(unionPtr) + hFile := debugInfo.File + if hFile != 0 && hFile != syscall.InvalidHandle { + err = syscall.CloseHandle(hFile) + if err != nil { + return 0, 0, err + } + } + dbp.os.hProcess = debugInfo.Process + _, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false, flags&waitSuspendNewThreads != 0) + if err != nil { + return 0, 0, err + } + break + case _CREATE_THREAD_DEBUG_EVENT: + debugInfo := (*_CREATE_THREAD_DEBUG_INFO)(unionPtr) + _, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false, flags&waitSuspendNewThreads != 0) + if err != nil { + return 0, 0, err + } + break + case _EXIT_THREAD_DEBUG_EVENT: + delete(dbp.threads, int(debugEvent.ThreadId)) + break + case _OUTPUT_DEBUG_STRING_EVENT: + //TODO: Handle debug output strings + break + case _LOAD_DLL_DEBUG_EVENT: + debugInfo := (*_LOAD_DLL_DEBUG_INFO)(unionPtr) + hFile := debugInfo.File + if hFile != 0 && hFile != syscall.InvalidHandle { + err = syscall.CloseHandle(hFile) + if err != nil { + return 0, 0, err + } + } + break + case _UNLOAD_DLL_DEBUG_EVENT: + break + case _RIP_EVENT: + break + case _EXCEPTION_DEBUG_EVENT: + exception := (*_EXCEPTION_DEBUG_INFO)(unionPtr) + tid := int(debugEvent.ThreadId) + + switch code := exception.ExceptionRecord.ExceptionCode; code { + case _EXCEPTION_BREAKPOINT: + + // check if the exception address really is a breakpoint instruction, if + // it isn't we already removed that breakpoint and we can't deal with + // this exception anymore. + atbp := true + if thread, found := dbp.threads[tid]; found { + if data, err := thread.readMemory(exception.ExceptionRecord.ExceptionAddress, dbp.arch.BreakpointSize()); err == nil { + instr := dbp.arch.BreakpointInstruction() + for i := range instr { + if data[i] != instr[i] { + atbp = false + break + } + } + } + if !atbp { + thread.SetPC(uint64(exception.ExceptionRecord.ExceptionAddress)) + } + } + + if atbp { + dbp.os.breakThread = tid + return tid, 0, nil + } else { + continueStatus = _DBG_CONTINUE + } + case _EXCEPTION_SINGLE_STEP: + dbp.os.breakThread = tid + return tid, 0, nil + default: + continueStatus = _DBG_EXCEPTION_NOT_HANDLED + } + case _EXIT_PROCESS_DEBUG_EVENT: + debugInfo := (*_EXIT_PROCESS_DEBUG_INFO)(unionPtr) + exitCode = int(debugInfo.ExitCode) + shouldExit = true + default: + return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.DebugEventCode) + } + + // .. and then continue unless we received an event that indicated we should break into debugger. + err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, continueStatus) + if err != nil { + return 0, 0, err + } + + if shouldExit { + return 0, exitCode, nil + } + } +} + +func (dbp *Process) trapWait(pid int) (*Thread, error) { + var err error + var tid, exitCode int + dbp.execPtraceFunc(func() { + tid, exitCode, err = dbp.waitForDebugEvent(waitBlocking) + }) + if err != nil { + return nil, err + } + if tid == 0 { + dbp.postExit() + return nil, ProcessExitedError{Pid: dbp.pid, Status: exitCode} + } + th := dbp.threads[tid] + return th, nil +} + +func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) { + wg.Done() +} + +func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) { + return 0, nil, fmt.Errorf("not implemented: wait") +} + +func (dbp *Process) setCurrentBreakpoints(trapthread *Thread) error { + // While the debug event that stopped the target was being propagated + // other target threads could generate other debug events. + // After this function we need to know about all the threads + // stopped on a breakpoint. To do that we first suspend all target + // threads and then repeatedly call _ContinueDebugEvent followed by + // waitForDebugEvent in non-blocking mode. + // We need to explicitly call SuspendThread because otherwise the + // call to _ContinueDebugEvent will resume execution of some of the + // target threads. + + err := trapthread.SetCurrentBreakpoint() + if err != nil { + return err + } + + for _, thread := range dbp.threads { + thread.running = false + _, err := _SuspendThread(thread.os.hThread) + if err != nil { + return err + } + } + + for { + var err error + var tid int + dbp.execPtraceFunc(func() { + err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE) + if err == nil { + tid, _, _ = dbp.waitForDebugEvent(waitSuspendNewThreads) + } + }) + if err != nil { + return err + } + if tid == 0 { + break + } + err = dbp.threads[tid].SetCurrentBreakpoint() + if err != nil { + return err + } + } + + return nil +} + +func (dbp *Process) exitGuard(err error) error { + return err +} + +func (dbp *Process) resume() error { + for _, thread := range dbp.threads { + if thread.CurrentBreakpoint != nil { + if err := thread.StepInstruction(); err != nil { + return err + } + thread.CurrentBreakpoint = nil + } + } + + for _, thread := range dbp.threads { + thread.running = true + _, err := _ResumeThread(thread.os.hThread) + if err != nil { + return err + } + } + + return nil +} + +func killProcess(pid int) error { + p, err := os.FindProcess(pid) + if err != nil { + return err + } + return p.Kill() +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/ptrace_darwin.go b/vendor/github.com/derekparker/delve/pkg/proc/ptrace_darwin.go new file mode 100644 index 0000000..c9ed435 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/ptrace_darwin.go @@ -0,0 +1,28 @@ +package proc + +import sys "golang.org/x/sys/unix" + +// PtraceAttach executes the sys.PtraceAttach call. +func PtraceAttach(pid int) error { + return sys.PtraceAttach(pid) +} + +// PtraceDetach executes the PT_DETACH ptrace call. +func PtraceDetach(tid, sig int) error { + return ptrace(sys.PT_DETACH, tid, 1, uintptr(sig)) +} + +// PtraceCont executes the PTRACE_CONT ptrace call. +func PtraceCont(tid, sig int) error { + return ptrace(sys.PTRACE_CONT, tid, 1, 0) +} + +// PtraceSingleStep returns PT_STEP ptrace call. +func PtraceSingleStep(tid int) error { + return ptrace(sys.PT_STEP, tid, 1, 0) +} + +func ptrace(request, pid int, addr uintptr, data uintptr) (err error) { + _, _, err = sys.Syscall6(sys.SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + return +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/ptrace_linux.go b/vendor/github.com/derekparker/delve/pkg/proc/ptrace_linux.go new file mode 100644 index 0000000..402dbb9 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/ptrace_linux.go @@ -0,0 +1,96 @@ +package proc + +import ( + "encoding/binary" + "syscall" + "unsafe" + + sys "golang.org/x/sys/unix" +) + +// PtraceAttach executes the sys.PtraceAttach call. +func PtraceAttach(pid int) error { + return sys.PtraceAttach(pid) +} + +// PtraceDetach calls ptrace(PTRACE_DETACH). +func PtraceDetach(tid, sig int) error { + _, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_DETACH, uintptr(tid), 1, uintptr(sig), 0, 0) + if err != syscall.Errno(0) { + return err + } + return nil +} + +// PtraceCont executes ptrace PTRACE_CONT +func PtraceCont(tid, sig int) error { + return sys.PtraceCont(tid, sig) +} + +// PtraceSingleStep executes ptrace PTRACE_SINGLE_STEP. +func PtraceSingleStep(tid int) error { + return sys.PtraceSingleStep(tid) +} + +// PtracePokeUser execute ptrace PTRACE_POKE_USER. +func PtracePokeUser(tid int, off, addr uintptr) error { + _, _, err := sys.Syscall6(sys.SYS_PTRACE, sys.PTRACE_POKEUSR, uintptr(tid), uintptr(off), uintptr(addr), 0, 0) + if err != syscall.Errno(0) { + return err + } + return nil +} + +// PtracePeekUser execute ptrace PTRACE_PEEK_USER. +func PtracePeekUser(tid int, off uintptr) (uintptr, error) { + var val uintptr + _, _, err := syscall.Syscall6(syscall.SYS_PTRACE, syscall.PTRACE_PEEKUSR, uintptr(tid), uintptr(off), uintptr(unsafe.Pointer(&val)), 0, 0) + if err != syscall.Errno(0) { + return 0, err + } + return val, nil +} + +// PtraceGetRegset returns floating point registers of the specified thread +// using PTRACE. +// See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.c.html +// and amd64_supply_xsave in gdb/amd64-tdep.c.html +// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture +func PtraceGetRegset(tid int) (regset PtraceXsave, err error) { + _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(®set.PtraceFpRegs)), 0, 0) + if err == syscall.Errno(0) { + err = nil + } + + var xstateargs [_X86_XSTATE_MAX_SIZE]byte + iov := sys.Iovec{Base: &xstateargs[0], Len: _X86_XSTATE_MAX_SIZE} + _, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0) + if err != syscall.Errno(0) { + return + } else { + err = nil + } + + if _XSAVE_HEADER_START+_XSAVE_HEADER_LEN >= iov.Len { + return + } + xsaveheader := xstateargs[_XSAVE_HEADER_START : _XSAVE_HEADER_START+_XSAVE_HEADER_LEN] + xstate_bv := binary.LittleEndian.Uint64(xsaveheader[0:8]) + xcomp_bv := binary.LittleEndian.Uint64(xsaveheader[8:16]) + + if xcomp_bv&(1<<63) != 0 { + // compact format not supported + return + } + + if xstate_bv&(1<<2) == 0 { + // AVX state not present + return + } + + avxstate := xstateargs[_XSAVE_EXTENDED_REGION_START:iov.Len] + regset.AvxState = true + copy(regset.YmmSpace[:], avxstate[:len(regset.YmmSpace)]) + + return +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/ptrace_windows.go b/vendor/github.com/derekparker/delve/pkg/proc/ptrace_windows.go new file mode 100644 index 0000000..96e347b --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/ptrace_windows.go @@ -0,0 +1,13 @@ +package proc + +import ( + "fmt" +) + +func PtraceAttach(pid int) error { + return fmt.Errorf("not implemented: PtraceAttach") +} + +func PtraceDetach(tid, sig int) error { + return _DebugActiveProcessStop(uint32(tid)) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/registers.go b/vendor/github.com/derekparker/delve/pkg/proc/registers.go new file mode 100644 index 0000000..4818ed5 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/registers.go @@ -0,0 +1,231 @@ +package proc + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "math" + "os" + "strings" +) + +// Registers is an interface for a generic register type. The +// interface encapsulates the generic values / actions +// we need independent of arch. The concrete register types +// will be different depending on OS/Arch. +type Registers interface { + PC() uint64 + SP() uint64 + BP() uint64 + CX() uint64 + TLS() uint64 + Get(int) (uint64, error) + SetPC(*Thread, uint64) error + Slice() []Register +} + +type Register struct { + Name string + Value string +} + +func appendWordReg(regs []Register, name string, value uint16) []Register { + return append(regs, Register{name, fmt.Sprintf("%#04x", value)}) +} + +func appendDwordReg(regs []Register, name string, value uint32) []Register { + return append(regs, Register{name, fmt.Sprintf("%#08x", value)}) +} + +func appendQwordReg(regs []Register, name string, value uint64) []Register { + return append(regs, Register{name, fmt.Sprintf("%#016x", value)}) +} + +func appendFlagReg(regs []Register, name string, value uint64, descr flagRegisterDescr, size int) []Register { + return append(regs, Register{name, descr.Describe(value, size)}) +} + +func appendX87Reg(regs []Register, index int, exponent uint16, mantissa uint64) []Register { + var f float64 + fset := false + + const ( + _SIGNBIT = 1 << 15 + _EXP_BIAS = (1 << 14) - 1 // 2^(n-1) - 1 = 16383 + _SPECIALEXP = (1 << 15) - 1 // all bits set + _HIGHBIT = 1 << 63 + _QUIETBIT = 1 << 62 + ) + + sign := 1.0 + if exponent&_SIGNBIT != 0 { + sign = -1.0 + } + exponent &= ^uint16(_SIGNBIT) + + NaN := math.NaN() + Inf := math.Inf(+1) + + switch exponent { + case 0: + switch { + case mantissa == 0: + f = sign * 0.0 + fset = true + case mantissa&_HIGHBIT != 0: + f = NaN + fset = true + } + case _SPECIALEXP: + switch { + case mantissa&_HIGHBIT == 0: + f = sign * Inf + fset = true + default: + f = NaN // signaling NaN + fset = true + } + default: + if mantissa&_HIGHBIT == 0 { + f = NaN + fset = true + } + } + + if !fset { + significand := float64(mantissa) / (1 << 63) + f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS)) + } + + return append(regs, Register{fmt.Sprintf("ST(%d)", index), fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)}) +} + +func appendSSEReg(regs []Register, name string, xmm []byte) []Register { + buf := bytes.NewReader(xmm) + + var out bytes.Buffer + var vi [16]uint8 + for i := range vi { + binary.Read(buf, binary.LittleEndian, &vi[i]) + } + + fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0]) + + fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8]) + + fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12]) + + fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14]) + + fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15]) + + buf.Seek(0, os.SEEK_SET) + var v2 [2]float64 + for i := range v2 { + binary.Read(buf, binary.LittleEndian, &v2[i]) + } + fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1]) + + buf.Seek(0, os.SEEK_SET) + var v4 [4]float32 + for i := range v4 { + binary.Read(buf, binary.LittleEndian, &v4[i]) + } + fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3]) + + return append(regs, Register{name, out.String()}) +} + +var UnknownRegisterError = errors.New("unknown register") + +// Registers obtains register values from the debugged process. +func (t *Thread) Registers(floatingPoint bool) (Registers, error) { + return registers(t, floatingPoint) +} + +// PC returns the current PC for this thread. +func (t *Thread) PC() (uint64, error) { + regs, err := t.Registers(false) + if err != nil { + return 0, err + } + return regs.PC(), nil +} + +type flagRegisterDescr []flagDescr +type flagDescr struct { + name string + mask uint64 +} + +var mxcsrDescription flagRegisterDescr = []flagDescr{ + {"FZ", 1 << 15}, + {"RZ/RN", 1<<14 | 1<<13}, + {"PM", 1 << 12}, + {"UM", 1 << 11}, + {"OM", 1 << 10}, + {"ZM", 1 << 9}, + {"DM", 1 << 8}, + {"IM", 1 << 7}, + {"DAZ", 1 << 6}, + {"PE", 1 << 5}, + {"UE", 1 << 4}, + {"OE", 1 << 3}, + {"ZE", 1 << 2}, + {"DE", 1 << 1}, + {"IE", 1 << 0}, +} + +var eflagsDescription flagRegisterDescr = []flagDescr{ + {"CF", 1 << 0}, + {"", 1 << 1}, + {"PF", 1 << 2}, + {"AF", 1 << 4}, + {"ZF", 1 << 6}, + {"SF", 1 << 7}, + {"TF", 1 << 8}, + {"IF", 1 << 9}, + {"DF", 1 << 10}, + {"OF", 1 << 11}, + {"IOPL", 1<<12 | 1<<13}, + {"NT", 1 << 14}, + {"RF", 1 << 16}, + {"VM", 1 << 17}, + {"AC", 1 << 18}, + {"VIF", 1 << 19}, + {"VIP", 1 << 20}, + {"ID", 1 << 21}, +} + +func (descr flagRegisterDescr) Mask() uint64 { + var r uint64 + for _, f := range descr { + r = r | f.mask + } + return r +} + +func (descr flagRegisterDescr) Describe(reg uint64, bitsize int) string { + var r []string + for _, f := range descr { + if f.name == "" { + continue + } + // rbm is f.mask with only the right-most bit set: + // 0001 1100 -> 0000 0100 + rbm := f.mask & -f.mask + if rbm == f.mask { + if reg&f.mask != 0 { + r = append(r, f.name) + } + } else { + x := (reg & f.mask) >> uint64(math.Log2(float64(rbm))) + r = append(r, fmt.Sprintf("%s=%x", f.name, x)) + } + } + if reg & ^descr.Mask() != 0 { + r = append(r, fmt.Sprintf("unknown_flags=%x", reg&^descr.Mask())) + } + return fmt.Sprintf("%#0*x\t[%s]", bitsize/4, reg, strings.Join(r, " ")) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/registers_darwin_amd64.go b/vendor/github.com/derekparker/delve/pkg/proc/registers_darwin_amd64.go new file mode 100644 index 0000000..4b3f8f1 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/registers_darwin_amd64.go @@ -0,0 +1,367 @@ +package proc + +// #include "threads_darwin.h" +import "C" +import ( + "encoding/binary" + "fmt" + "rsc.io/x86/x86asm" + "unsafe" +) + +// Regs represents CPU registers on an AMD64 processor. +type Regs struct { + rax uint64 + rbx uint64 + rcx uint64 + rdx uint64 + rdi uint64 + rsi uint64 + rbp uint64 + rsp uint64 + r8 uint64 + r9 uint64 + r10 uint64 + r11 uint64 + r12 uint64 + r13 uint64 + r14 uint64 + r15 uint64 + rip uint64 + rflags uint64 + cs uint64 + fs uint64 + gs uint64 + gsBase uint64 + fpregs []Register +} + +func (r *Regs) Slice() []Register { + var regs = []struct { + k string + v uint64 + }{ + {"Rip", r.rip}, + {"Rsp", r.rsp}, + {"Rax", r.rax}, + {"Rbx", r.rbx}, + {"Rcx", r.rcx}, + {"Rdx", r.rdx}, + {"Rdi", r.rdi}, + {"Rsi", r.rsi}, + {"Rbp", r.rbp}, + {"R8", r.r8}, + {"R9", r.r9}, + {"R10", r.r10}, + {"R11", r.r11}, + {"R12", r.r12}, + {"R13", r.r13}, + {"R14", r.r14}, + {"R15", r.r15}, + {"Rflags", r.rflags}, + {"Cs", r.cs}, + {"Fs", r.fs}, + {"Gs", r.gs}, + {"Gs_base", r.gsBase}, + } + out := make([]Register, 0, len(regs)+len(r.fpregs)) + for _, reg := range regs { + if reg.k == "Rflags" { + out = appendFlagReg(out, reg.k, reg.v, eflagsDescription, 64) + } else { + out = appendQwordReg(out, reg.k, reg.v) + } + } + out = append(out, r.fpregs...) + return out +} + +// PC returns the current program counter +// i.e. the RIP CPU register. +func (r *Regs) PC() uint64 { + return r.rip +} + +// SP returns the stack pointer location, +// i.e. the RSP register. +func (r *Regs) SP() uint64 { + return r.rsp +} + +func (r *Regs) BP() uint64 { + return r.rbp +} + +// CX returns the value of the RCX register. +func (r *Regs) CX() uint64 { + return r.rcx +} + +// TLS returns the value of the register +// that contains the location of the thread +// local storage segment. +func (r *Regs) TLS() uint64 { + return r.gsBase +} + +// SetPC sets the RIP register to the value specified by `pc`. +func (r *Regs) SetPC(thread *Thread, pc uint64) error { + kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc)) + if kret != C.KERN_SUCCESS { + return fmt.Errorf("could not set pc") + } + return nil +} + +func (r *Regs) Get(n int) (uint64, error) { + reg := x86asm.Reg(n) + const ( + mask8 = 0x000f + mask16 = 0x00ff + mask32 = 0xffff + ) + + switch reg { + // 8-bit + case x86asm.AL: + return r.rax & mask8, nil + case x86asm.CL: + return r.rcx & mask8, nil + case x86asm.DL: + return r.rdx & mask8, nil + case x86asm.BL: + return r.rbx & mask8, nil + case x86asm.AH: + return (r.rax >> 8) & mask8, nil + case x86asm.CH: + return (r.rcx >> 8) & mask8, nil + case x86asm.DH: + return (r.rdx >> 8) & mask8, nil + case x86asm.BH: + return (r.rbx >> 8) & mask8, nil + case x86asm.SPB: + return r.rsp & mask8, nil + case x86asm.BPB: + return r.rbp & mask8, nil + case x86asm.SIB: + return r.rsi & mask8, nil + case x86asm.DIB: + return r.rdi & mask8, nil + case x86asm.R8B: + return r.r8 & mask8, nil + case x86asm.R9B: + return r.r9 & mask8, nil + case x86asm.R10B: + return r.r10 & mask8, nil + case x86asm.R11B: + return r.r11 & mask8, nil + case x86asm.R12B: + return r.r12 & mask8, nil + case x86asm.R13B: + return r.r13 & mask8, nil + case x86asm.R14B: + return r.r14 & mask8, nil + case x86asm.R15B: + return r.r15 & mask8, nil + + // 16-bit + case x86asm.AX: + return r.rax & mask16, nil + case x86asm.CX: + return r.rcx & mask16, nil + case x86asm.DX: + return r.rdx & mask16, nil + case x86asm.BX: + return r.rbx & mask16, nil + case x86asm.SP: + return r.rsp & mask16, nil + case x86asm.BP: + return r.rbp & mask16, nil + case x86asm.SI: + return r.rsi & mask16, nil + case x86asm.DI: + return r.rdi & mask16, nil + case x86asm.R8W: + return r.r8 & mask16, nil + case x86asm.R9W: + return r.r9 & mask16, nil + case x86asm.R10W: + return r.r10 & mask16, nil + case x86asm.R11W: + return r.r11 & mask16, nil + case x86asm.R12W: + return r.r12 & mask16, nil + case x86asm.R13W: + return r.r13 & mask16, nil + case x86asm.R14W: + return r.r14 & mask16, nil + case x86asm.R15W: + return r.r15 & mask16, nil + + // 32-bit + case x86asm.EAX: + return r.rax & mask32, nil + case x86asm.ECX: + return r.rcx & mask32, nil + case x86asm.EDX: + return r.rdx & mask32, nil + case x86asm.EBX: + return r.rbx & mask32, nil + case x86asm.ESP: + return r.rsp & mask32, nil + case x86asm.EBP: + return r.rbp & mask32, nil + case x86asm.ESI: + return r.rsi & mask32, nil + case x86asm.EDI: + return r.rdi & mask32, nil + case x86asm.R8L: + return r.r8 & mask32, nil + case x86asm.R9L: + return r.r9 & mask32, nil + case x86asm.R10L: + return r.r10 & mask32, nil + case x86asm.R11L: + return r.r11 & mask32, nil + case x86asm.R12L: + return r.r12 & mask32, nil + case x86asm.R13L: + return r.r13 & mask32, nil + case x86asm.R14L: + return r.r14 & mask32, nil + case x86asm.R15L: + return r.r15 & mask32, nil + + // 64-bit + case x86asm.RAX: + return r.rax, nil + case x86asm.RCX: + return r.rcx, nil + case x86asm.RDX: + return r.rdx, nil + case x86asm.RBX: + return r.rbx, nil + case x86asm.RSP: + return r.rsp, nil + case x86asm.RBP: + return r.rbp, nil + case x86asm.RSI: + return r.rsi, nil + case x86asm.RDI: + return r.rdi, nil + case x86asm.R8: + return r.r8, nil + case x86asm.R9: + return r.r9, nil + case x86asm.R10: + return r.r10, nil + case x86asm.R11: + return r.r11, nil + case x86asm.R12: + return r.r12, nil + case x86asm.R13: + return r.r13, nil + case x86asm.R14: + return r.r14, nil + case x86asm.R15: + return r.r15, nil + } + + return 0, UnknownRegisterError +} + +func registers(thread *Thread, floatingPoint bool) (Registers, error) { + var state C.x86_thread_state64_t + var identity C.thread_identifier_info_data_t + kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state) + if kret != C.KERN_SUCCESS { + return nil, fmt.Errorf("could not get registers") + } + kret = C.get_identity(C.mach_port_name_t(thread.os.threadAct), &identity) + if kret != C.KERN_SUCCESS { + return nil, fmt.Errorf("could not get thread identity informations") + } + /* + thread_identifier_info::thread_handle contains the base of the + thread-specific data area, which on x86 and x86_64 is the thread’s base + address of the %gs segment. 10.9.2 xnu-2422.90.20/osfmk/kern/thread.c + thread_info_internal() gets the value from + machine_thread::cthread_self, which is the same value used to set the + %gs base in xnu-2422.90.20/osfmk/i386/pcb_native.c + act_machine_switch_pcb(). + -- + comment copied from chromium's crashpad + https://chromium.googlesource.com/crashpad/crashpad/+/master/snapshot/mac/process_reader.cc + */ + regs := &Regs{ + rax: uint64(state.__rax), + rbx: uint64(state.__rbx), + rcx: uint64(state.__rcx), + rdx: uint64(state.__rdx), + rdi: uint64(state.__rdi), + rsi: uint64(state.__rsi), + rbp: uint64(state.__rbp), + rsp: uint64(state.__rsp), + r8: uint64(state.__r8), + r9: uint64(state.__r9), + r10: uint64(state.__r10), + r11: uint64(state.__r11), + r12: uint64(state.__r12), + r13: uint64(state.__r13), + r14: uint64(state.__r14), + r15: uint64(state.__r15), + rip: uint64(state.__rip), + rflags: uint64(state.__rflags), + cs: uint64(state.__cs), + fs: uint64(state.__fs), + gs: uint64(state.__gs), + gsBase: uint64(identity.thread_handle), + } + + if floatingPoint { + // https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/thread_status.h?txt + var fpstate C.x86_float_state64_t + kret = C.get_fpu_registers(C.mach_port_name_t(thread.os.threadAct), &fpstate) + if kret != C.KERN_SUCCESS { + return nil, fmt.Errorf("could not get floating point registers") + } + + regs.fpregs = appendWordReg(regs.fpregs, "CW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw)))) + regs.fpregs = appendWordReg(regs.fpregs, "SW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw)))) + regs.fpregs = appendWordReg(regs.fpregs, "TW", uint16(fpstate.__fpu_ftw)) + regs.fpregs = appendWordReg(regs.fpregs, "FOP", uint16(fpstate.__fpu_fop)) + regs.fpregs = appendQwordReg(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip)) + regs.fpregs = appendQwordReg(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp)) + + for i, st := range []*C.char{&fpstate.__fpu_stmm0.__mmst_reg[0], &fpstate.__fpu_stmm1.__mmst_reg[0], &fpstate.__fpu_stmm2.__mmst_reg[0], &fpstate.__fpu_stmm3.__mmst_reg[0], &fpstate.__fpu_stmm4.__mmst_reg[0], &fpstate.__fpu_stmm5.__mmst_reg[0], &fpstate.__fpu_stmm6.__mmst_reg[0], &fpstate.__fpu_stmm7.__mmst_reg[0]} { + stb := C.GoBytes(unsafe.Pointer(st), 10) + mantissa := binary.LittleEndian.Uint64(stb[:8]) + exponent := binary.LittleEndian.Uint16(stb[8:]) + regs.fpregs = appendX87Reg(regs.fpregs, i, exponent, mantissa) + } + + regs.fpregs = appendFlagReg(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr), mxcsrDescription, 32) + regs.fpregs = appendDwordReg(regs.fpregs, "MXCSR_MASK", uint32(fpstate.__fpu_mxcsrmask)) + + for i, xmm := range []*C.char{&fpstate.__fpu_xmm0.__xmm_reg[0], &fpstate.__fpu_xmm1.__xmm_reg[0], &fpstate.__fpu_xmm2.__xmm_reg[0], &fpstate.__fpu_xmm3.__xmm_reg[0], &fpstate.__fpu_xmm4.__xmm_reg[0], &fpstate.__fpu_xmm5.__xmm_reg[0], &fpstate.__fpu_xmm6.__xmm_reg[0], &fpstate.__fpu_xmm7.__xmm_reg[0], &fpstate.__fpu_xmm8.__xmm_reg[0], &fpstate.__fpu_xmm9.__xmm_reg[0], &fpstate.__fpu_xmm10.__xmm_reg[0], &fpstate.__fpu_xmm11.__xmm_reg[0], &fpstate.__fpu_xmm12.__xmm_reg[0], &fpstate.__fpu_xmm13.__xmm_reg[0], &fpstate.__fpu_xmm14.__xmm_reg[0], &fpstate.__fpu_xmm15.__xmm_reg[0]} { + regs.fpregs = appendSSEReg(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16)) + } + } + return regs, nil +} + +func (thread *Thread) saveRegisters() (Registers, error) { + kret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &thread.os.registers) + if kret != C.KERN_SUCCESS { + return nil, fmt.Errorf("could not save register contents") + } + return &Regs{rip: uint64(thread.os.registers.__rip), rsp: uint64(thread.os.registers.__rsp)}, nil +} + +func (thread *Thread) restoreRegisters() error { + kret := C.set_registers(C.mach_port_name_t(thread.os.threadAct), &thread.os.registers) + if kret != C.KERN_SUCCESS { + return fmt.Errorf("could not save register contents") + } + return nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/registers_linux_amd64.go b/vendor/github.com/derekparker/delve/pkg/proc/registers_linux_amd64.go new file mode 100644 index 0000000..4b7f6a7 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/registers_linux_amd64.go @@ -0,0 +1,329 @@ +package proc + +import ( + "fmt" + + "rsc.io/x86/x86asm" + + sys "golang.org/x/sys/unix" +) + +// Regs is a wrapper for sys.PtraceRegs. +type Regs struct { + regs *sys.PtraceRegs + fpregs []Register +} + +func (r *Regs) Slice() []Register { + var regs = []struct { + k string + v uint64 + }{ + {"Rip", r.regs.Rip}, + {"Rsp", r.regs.Rsp}, + {"Rax", r.regs.Rax}, + {"Rbx", r.regs.Rbx}, + {"Rcx", r.regs.Rcx}, + {"Rdx", r.regs.Rdx}, + {"Rdi", r.regs.Rdi}, + {"Rsi", r.regs.Rsi}, + {"Rbp", r.regs.Rbp}, + {"R8", r.regs.R8}, + {"R9", r.regs.R9}, + {"R10", r.regs.R10}, + {"R11", r.regs.R11}, + {"R12", r.regs.R12}, + {"R13", r.regs.R13}, + {"R14", r.regs.R14}, + {"R15", r.regs.R15}, + {"Orig_rax", r.regs.Orig_rax}, + {"Cs", r.regs.Cs}, + {"Eflags", r.regs.Eflags}, + {"Ss", r.regs.Ss}, + {"Fs_base", r.regs.Fs_base}, + {"Gs_base", r.regs.Gs_base}, + {"Ds", r.regs.Ds}, + {"Es", r.regs.Es}, + {"Fs", r.regs.Fs}, + {"Gs", r.regs.Gs}, + } + out := make([]Register, 0, len(regs)+len(r.fpregs)) + for _, reg := range regs { + if reg.k == "Eflags" { + out = appendFlagReg(out, reg.k, reg.v, eflagsDescription, 64) + } else { + out = appendQwordReg(out, reg.k, reg.v) + } + } + out = append(out, r.fpregs...) + return out +} + +// PC returns the value of RIP register. +func (r *Regs) PC() uint64 { + return r.regs.PC() +} + +// SP returns the value of RSP register. +func (r *Regs) SP() uint64 { + return r.regs.Rsp +} + +func (r *Regs) BP() uint64 { + return r.regs.Rbp +} + +// CX returns the value of RCX register. +func (r *Regs) CX() uint64 { + return r.regs.Rcx +} + +// TLS returns the address of the thread +// local storage memory segment. +func (r *Regs) TLS() uint64 { + return r.regs.Fs_base +} + +// SetPC sets RIP to the value specified by 'pc'. +func (r *Regs) SetPC(thread *Thread, pc uint64) (err error) { + r.regs.SetPC(pc) + thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.ID, r.regs) }) + return +} + +func (r *Regs) Get(n int) (uint64, error) { + reg := x86asm.Reg(n) + const ( + mask8 = 0x000f + mask16 = 0x00ff + mask32 = 0xffff + ) + + switch reg { + // 8-bit + case x86asm.AL: + return r.regs.Rax & mask8, nil + case x86asm.CL: + return r.regs.Rcx & mask8, nil + case x86asm.DL: + return r.regs.Rdx & mask8, nil + case x86asm.BL: + return r.regs.Rbx & mask8, nil + case x86asm.AH: + return (r.regs.Rax >> 8) & mask8, nil + case x86asm.CH: + return (r.regs.Rcx >> 8) & mask8, nil + case x86asm.DH: + return (r.regs.Rdx >> 8) & mask8, nil + case x86asm.BH: + return (r.regs.Rbx >> 8) & mask8, nil + case x86asm.SPB: + return r.regs.Rsp & mask8, nil + case x86asm.BPB: + return r.regs.Rbp & mask8, nil + case x86asm.SIB: + return r.regs.Rsi & mask8, nil + case x86asm.DIB: + return r.regs.Rdi & mask8, nil + case x86asm.R8B: + return r.regs.R8 & mask8, nil + case x86asm.R9B: + return r.regs.R9 & mask8, nil + case x86asm.R10B: + return r.regs.R10 & mask8, nil + case x86asm.R11B: + return r.regs.R11 & mask8, nil + case x86asm.R12B: + return r.regs.R12 & mask8, nil + case x86asm.R13B: + return r.regs.R13 & mask8, nil + case x86asm.R14B: + return r.regs.R14 & mask8, nil + case x86asm.R15B: + return r.regs.R15 & mask8, nil + + // 16-bit + case x86asm.AX: + return r.regs.Rax & mask16, nil + case x86asm.CX: + return r.regs.Rcx & mask16, nil + case x86asm.DX: + return r.regs.Rdx & mask16, nil + case x86asm.BX: + return r.regs.Rbx & mask16, nil + case x86asm.SP: + return r.regs.Rsp & mask16, nil + case x86asm.BP: + return r.regs.Rbp & mask16, nil + case x86asm.SI: + return r.regs.Rsi & mask16, nil + case x86asm.DI: + return r.regs.Rdi & mask16, nil + case x86asm.R8W: + return r.regs.R8 & mask16, nil + case x86asm.R9W: + return r.regs.R9 & mask16, nil + case x86asm.R10W: + return r.regs.R10 & mask16, nil + case x86asm.R11W: + return r.regs.R11 & mask16, nil + case x86asm.R12W: + return r.regs.R12 & mask16, nil + case x86asm.R13W: + return r.regs.R13 & mask16, nil + case x86asm.R14W: + return r.regs.R14 & mask16, nil + case x86asm.R15W: + return r.regs.R15 & mask16, nil + + // 32-bit + case x86asm.EAX: + return r.regs.Rax & mask32, nil + case x86asm.ECX: + return r.regs.Rcx & mask32, nil + case x86asm.EDX: + return r.regs.Rdx & mask32, nil + case x86asm.EBX: + return r.regs.Rbx & mask32, nil + case x86asm.ESP: + return r.regs.Rsp & mask32, nil + case x86asm.EBP: + return r.regs.Rbp & mask32, nil + case x86asm.ESI: + return r.regs.Rsi & mask32, nil + case x86asm.EDI: + return r.regs.Rdi & mask32, nil + case x86asm.R8L: + return r.regs.R8 & mask32, nil + case x86asm.R9L: + return r.regs.R9 & mask32, nil + case x86asm.R10L: + return r.regs.R10 & mask32, nil + case x86asm.R11L: + return r.regs.R11 & mask32, nil + case x86asm.R12L: + return r.regs.R12 & mask32, nil + case x86asm.R13L: + return r.regs.R13 & mask32, nil + case x86asm.R14L: + return r.regs.R14 & mask32, nil + case x86asm.R15L: + return r.regs.R15 & mask32, nil + + // 64-bit + case x86asm.RAX: + return r.regs.Rax, nil + case x86asm.RCX: + return r.regs.Rcx, nil + case x86asm.RDX: + return r.regs.Rdx, nil + case x86asm.RBX: + return r.regs.Rbx, nil + case x86asm.RSP: + return r.regs.Rsp, nil + case x86asm.RBP: + return r.regs.Rbp, nil + case x86asm.RSI: + return r.regs.Rsi, nil + case x86asm.RDI: + return r.regs.Rdi, nil + case x86asm.R8: + return r.regs.R8, nil + case x86asm.R9: + return r.regs.R9, nil + case x86asm.R10: + return r.regs.R10, nil + case x86asm.R11: + return r.regs.R11, nil + case x86asm.R12: + return r.regs.R12, nil + case x86asm.R13: + return r.regs.R13, nil + case x86asm.R14: + return r.regs.R14, nil + case x86asm.R15: + return r.regs.R15, nil + } + + return 0, UnknownRegisterError +} + +func registers(thread *Thread, floatingPoint bool) (Registers, error) { + var ( + regs sys.PtraceRegs + err error + ) + thread.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(thread.ID, ®s) }) + if err != nil { + return nil, err + } + r := &Regs{®s, nil} + if floatingPoint { + r.fpregs, err = thread.fpRegisters() + if err != nil { + return nil, err + } + } + return r, nil +} + +// tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h +type PtraceFpRegs struct { + Cwd uint16 + Swd uint16 + Ftw uint16 + Fop uint16 + Rip uint64 + Rdp uint64 + Mxcsr uint32 + MxcrMask uint32 + StSpace [32]uint32 + XmmSpace [256]byte + padding [24]uint32 +} + +type PtraceXsave struct { + PtraceFpRegs + AvxState bool // contains AVX state + YmmSpace [256]byte +} + +const ( + _X86_XSTATE_MAX_SIZE = 2688 + _NT_X86_XSTATE = 0x202 + + _XSAVE_HEADER_START = 512 + _XSAVE_HEADER_LEN = 64 + _XSAVE_EXTENDED_REGION_START = 576 + _XSAVE_SSE_REGION_LEN = 416 +) + +func (thread *Thread) fpRegisters() (regs []Register, err error) { + var fpregs PtraceXsave + thread.dbp.execPtraceFunc(func() { fpregs, err = PtraceGetRegset(thread.ID) }) + + // x87 registers + regs = appendWordReg(regs, "CW", fpregs.Cwd) + regs = appendWordReg(regs, "SW", fpregs.Swd) + regs = appendWordReg(regs, "TW", fpregs.Ftw) + regs = appendWordReg(regs, "FOP", fpregs.Fop) + regs = appendQwordReg(regs, "FIP", fpregs.Rip) + regs = appendQwordReg(regs, "FDP", fpregs.Rdp) + + for i := 0; i < len(fpregs.StSpace); i += 4 { + regs = appendX87Reg(regs, i/4, uint16(fpregs.StSpace[i+2]), uint64(fpregs.StSpace[i+1])<<32|uint64(fpregs.StSpace[i])) + } + + // SSE registers + regs = appendFlagReg(regs, "MXCSR", uint64(fpregs.Mxcsr), mxcsrDescription, 32) + regs = appendDwordReg(regs, "MXCSR_MASK", fpregs.MxcrMask) + + for i := 0; i < len(fpregs.XmmSpace); i += 16 { + regs = appendSSEReg(regs, fmt.Sprintf("XMM%d", i/16), fpregs.XmmSpace[i:i+16]) + if fpregs.AvxState { + regs = appendSSEReg(regs, fmt.Sprintf("YMM%d", i/16), fpregs.YmmSpace[i:i+16]) + } + } + + return +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/registers_windows_amd64.go b/vendor/github.com/derekparker/delve/pkg/proc/registers_windows_amd64.go new file mode 100644 index 0000000..23ff6e8 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/registers_windows_amd64.go @@ -0,0 +1,351 @@ +package proc + +import ( + "fmt" + "rsc.io/x86/x86asm" + "unsafe" +) + +// Regs represents CPU registers on an AMD64 processor. +type Regs struct { + rax uint64 + rbx uint64 + rcx uint64 + rdx uint64 + rdi uint64 + rsi uint64 + rbp uint64 + rsp uint64 + r8 uint64 + r9 uint64 + r10 uint64 + r11 uint64 + r12 uint64 + r13 uint64 + r14 uint64 + r15 uint64 + rip uint64 + eflags uint64 + cs uint64 + fs uint64 + gs uint64 + tls uint64 + fltSave *_XMM_SAVE_AREA32 +} + +func (r *Regs) Slice() []Register { + var regs = []struct { + k string + v uint64 + }{ + {"Rip", r.rip}, + {"Rsp", r.rsp}, + {"Rax", r.rax}, + {"Rbx", r.rbx}, + {"Rcx", r.rcx}, + {"Rdx", r.rdx}, + {"Rdi", r.rdi}, + {"Rsi", r.rsi}, + {"Rbp", r.rbp}, + {"R8", r.r8}, + {"R9", r.r9}, + {"R10", r.r10}, + {"R11", r.r11}, + {"R12", r.r12}, + {"R13", r.r13}, + {"R14", r.r14}, + {"R15", r.r15}, + {"Eflags", r.eflags}, + {"Cs", r.cs}, + {"Fs", r.fs}, + {"Gs", r.gs}, + {"TLS", r.tls}, + } + outlen := len(regs) + if r.fltSave != nil { + outlen += 6 + 8 + 2 + 16 + } + out := make([]Register, 0, outlen) + for _, reg := range regs { + if reg.k == "Eflags" { + out = append(out, Register{reg.k, eflagsDescription.Describe(reg.v, 64)}) + } else { + out = appendQwordReg(out, reg.k, reg.v) + } + } + if r.fltSave != nil { + out = appendWordReg(out, "CW", r.fltSave.ControlWord) + out = appendWordReg(out, "SW", r.fltSave.StatusWord) + out = appendWordReg(out, "TW", uint16(r.fltSave.TagWord)) + out = appendWordReg(out, "FOP", r.fltSave.ErrorOpcode) + out = appendQwordReg(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset)) + out = appendQwordReg(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset)) + + for i := range r.fltSave.FloatRegisters { + out = appendX87Reg(out, i, uint16(r.fltSave.FloatRegisters[i].High), r.fltSave.FloatRegisters[i].Low) + } + + out = appendFlagReg(out, "MXCSR", uint64(r.fltSave.MxCsr), mxcsrDescription, 32) + out = appendDwordReg(out, "MXCSR_MASK", r.fltSave.MxCsr_Mask) + + for i := 0; i < len(r.fltSave.XmmRegisters); i += 16 { + out = appendSSEReg(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16]) + } + } + return out +} + +// PC returns the current program counter +// i.e. the RIP CPU register. +func (r *Regs) PC() uint64 { + return r.rip +} + +// SP returns the stack pointer location, +// i.e. the RSP register. +func (r *Regs) SP() uint64 { + return r.rsp +} + +func (r *Regs) BP() uint64 { + return r.rbp +} + +// CX returns the value of the RCX register. +func (r *Regs) CX() uint64 { + return r.rcx +} + +// TLS returns the value of the register +// that contains the location of the thread +// local storage segment. +func (r *Regs) TLS() uint64 { + return r.tls +} + +// SetPC sets the RIP register to the value specified by `pc`. +func (r *Regs) SetPC(thread *Thread, pc uint64) error { + context := newCONTEXT() + context.ContextFlags = _CONTEXT_ALL + + err := _GetThreadContext(thread.os.hThread, context) + if err != nil { + return err + } + + context.Rip = pc + + return _SetThreadContext(thread.os.hThread, context) +} + +func (r *Regs) Get(n int) (uint64, error) { + reg := x86asm.Reg(n) + const ( + mask8 = 0x000f + mask16 = 0x00ff + mask32 = 0xffff + ) + + switch reg { + // 8-bit + case x86asm.AL: + return r.rax & mask8, nil + case x86asm.CL: + return r.rcx & mask8, nil + case x86asm.DL: + return r.rdx & mask8, nil + case x86asm.BL: + return r.rbx & mask8, nil + case x86asm.AH: + return (r.rax >> 8) & mask8, nil + case x86asm.CH: + return (r.rcx >> 8) & mask8, nil + case x86asm.DH: + return (r.rdx >> 8) & mask8, nil + case x86asm.BH: + return (r.rbx >> 8) & mask8, nil + case x86asm.SPB: + return r.rsp & mask8, nil + case x86asm.BPB: + return r.rbp & mask8, nil + case x86asm.SIB: + return r.rsi & mask8, nil + case x86asm.DIB: + return r.rdi & mask8, nil + case x86asm.R8B: + return r.r8 & mask8, nil + case x86asm.R9B: + return r.r9 & mask8, nil + case x86asm.R10B: + return r.r10 & mask8, nil + case x86asm.R11B: + return r.r11 & mask8, nil + case x86asm.R12B: + return r.r12 & mask8, nil + case x86asm.R13B: + return r.r13 & mask8, nil + case x86asm.R14B: + return r.r14 & mask8, nil + case x86asm.R15B: + return r.r15 & mask8, nil + + // 16-bit + case x86asm.AX: + return r.rax & mask16, nil + case x86asm.CX: + return r.rcx & mask16, nil + case x86asm.DX: + return r.rdx & mask16, nil + case x86asm.BX: + return r.rbx & mask16, nil + case x86asm.SP: + return r.rsp & mask16, nil + case x86asm.BP: + return r.rbp & mask16, nil + case x86asm.SI: + return r.rsi & mask16, nil + case x86asm.DI: + return r.rdi & mask16, nil + case x86asm.R8W: + return r.r8 & mask16, nil + case x86asm.R9W: + return r.r9 & mask16, nil + case x86asm.R10W: + return r.r10 & mask16, nil + case x86asm.R11W: + return r.r11 & mask16, nil + case x86asm.R12W: + return r.r12 & mask16, nil + case x86asm.R13W: + return r.r13 & mask16, nil + case x86asm.R14W: + return r.r14 & mask16, nil + case x86asm.R15W: + return r.r15 & mask16, nil + + // 32-bit + case x86asm.EAX: + return r.rax & mask32, nil + case x86asm.ECX: + return r.rcx & mask32, nil + case x86asm.EDX: + return r.rdx & mask32, nil + case x86asm.EBX: + return r.rbx & mask32, nil + case x86asm.ESP: + return r.rsp & mask32, nil + case x86asm.EBP: + return r.rbp & mask32, nil + case x86asm.ESI: + return r.rsi & mask32, nil + case x86asm.EDI: + return r.rdi & mask32, nil + case x86asm.R8L: + return r.r8 & mask32, nil + case x86asm.R9L: + return r.r9 & mask32, nil + case x86asm.R10L: + return r.r10 & mask32, nil + case x86asm.R11L: + return r.r11 & mask32, nil + case x86asm.R12L: + return r.r12 & mask32, nil + case x86asm.R13L: + return r.r13 & mask32, nil + case x86asm.R14L: + return r.r14 & mask32, nil + case x86asm.R15L: + return r.r15 & mask32, nil + + // 64-bit + case x86asm.RAX: + return r.rax, nil + case x86asm.RCX: + return r.rcx, nil + case x86asm.RDX: + return r.rdx, nil + case x86asm.RBX: + return r.rbx, nil + case x86asm.RSP: + return r.rsp, nil + case x86asm.RBP: + return r.rbp, nil + case x86asm.RSI: + return r.rsi, nil + case x86asm.RDI: + return r.rdi, nil + case x86asm.R8: + return r.r8, nil + case x86asm.R9: + return r.r9, nil + case x86asm.R10: + return r.r10, nil + case x86asm.R11: + return r.r11, nil + case x86asm.R12: + return r.r12, nil + case x86asm.R13: + return r.r13, nil + case x86asm.R14: + return r.r14, nil + case x86asm.R15: + return r.r15, nil + } + + return 0, UnknownRegisterError +} + +func registers(thread *Thread, floatingPoint bool) (Registers, error) { + context := newCONTEXT() + + context.ContextFlags = _CONTEXT_ALL + err := _GetThreadContext(thread.os.hThread, context) + if err != nil { + return nil, err + } + + var threadInfo _THREAD_BASIC_INFORMATION + status := _NtQueryInformationThread(thread.os.hThread, _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil) + if !_NT_SUCCESS(status) { + return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status) + } + + regs := &Regs{ + rax: uint64(context.Rax), + rbx: uint64(context.Rbx), + rcx: uint64(context.Rcx), + rdx: uint64(context.Rdx), + rdi: uint64(context.Rdi), + rsi: uint64(context.Rsi), + rbp: uint64(context.Rbp), + rsp: uint64(context.Rsp), + r8: uint64(context.R8), + r9: uint64(context.R9), + r10: uint64(context.R10), + r11: uint64(context.R11), + r12: uint64(context.R12), + r13: uint64(context.R13), + r14: uint64(context.R14), + r15: uint64(context.R15), + rip: uint64(context.Rip), + eflags: uint64(context.EFlags), + cs: uint64(context.SegCs), + fs: uint64(context.SegFs), + gs: uint64(context.SegGs), + tls: uint64(threadInfo.TebBaseAddress), + } + + if floatingPoint { + regs.fltSave = &context.FltSave + } + + return regs, nil +} + +func (thread *Thread) saveRegisters() (Registers, error) { + return nil, fmt.Errorf("not implemented: saveRegisters") +} + +func (thread *Thread) restoreRegisters() error { + return fmt.Errorf("not implemented: restoreRegisters") +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/stack.go b/vendor/github.com/derekparker/delve/pkg/proc/stack.go new file mode 100644 index 0000000..df5cd67 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/stack.go @@ -0,0 +1,261 @@ +package proc + +import ( + "errors" + "fmt" + + "github.com/derekparker/delve/pkg/dwarf/frame" +) + +// This code is partly adaped from runtime.gentraceback in +// $GOROOT/src/runtime/traceback.go + +const runtimeStackBarrier = "runtime.stackBarrier" + +// NoReturnAddr is returned when return address +// could not be found during stack trace. +type NoReturnAddr struct { + fn string +} + +func (nra NoReturnAddr) Error() string { + return fmt.Sprintf("could not find return address for %s", nra.fn) +} + +// Stackframe represents a frame in a system stack. +type Stackframe struct { + // Address the function above this one on the call stack will return to. + Current Location + // Address of the call instruction for the function above on the call stack. + Call Location + // Start address of the stack frame. + CFA int64 + // Description of the stack frame. + FDE *frame.FrameDescriptionEntry + // Return address for this stack frame (as read from the stack frame itself). + Ret uint64 + // Address to the memory location containing the return address + addrret uint64 +} + +// Scope returns a new EvalScope using this frame. +func (frame *Stackframe) Scope(thread *Thread) *EvalScope { + return &EvalScope{Thread: thread, PC: frame.Current.PC, CFA: frame.CFA} +} + +// ReturnAddress returns the return address of the function +// this thread is executing. +func (t *Thread) ReturnAddress() (uint64, error) { + locations, err := t.Stacktrace(2) + if err != nil { + return 0, err + } + if len(locations) < 2 { + return 0, NoReturnAddr{locations[0].Current.Fn.BaseName()} + } + return locations[1].Current.PC, nil +} + +func (t *Thread) stackIterator(stkbar []savedLR, stkbarPos int) (*stackIterator, error) { + regs, err := t.Registers(false) + if err != nil { + return nil, err + } + return newStackIterator(t.dbp, regs.PC(), regs.SP(), regs.BP(), stkbar, stkbarPos), nil +} + +// Stacktrace returns the stack trace for thread. +// Note the locations in the array are return addresses not call addresses. +func (t *Thread) Stacktrace(depth int) ([]Stackframe, error) { + it, err := t.stackIterator(nil, -1) + if err != nil { + return nil, err + } + return it.stacktrace(depth) +} + +func (g *G) stackIterator() (*stackIterator, error) { + stkbar, err := g.stkbar() + if err != nil { + return nil, err + } + if g.thread != nil { + return g.thread.stackIterator(stkbar, g.stkbarPos) + } + return newStackIterator(g.dbp, g.PC, g.SP, 0, stkbar, g.stkbarPos), nil +} + +// Stacktrace returns the stack trace for a goroutine. +// Note the locations in the array are return addresses not call addresses. +func (g *G) Stacktrace(depth int) ([]Stackframe, error) { + it, err := g.stackIterator() + if err != nil { + return nil, err + } + return it.stacktrace(depth) +} + +// GoroutineLocation returns the location of the given +// goroutine. +func (dbp *Process) GoroutineLocation(g *G) *Location { + f, l, fn := dbp.PCToLine(g.PC) + return &Location{PC: g.PC, File: f, Line: l, Fn: fn} +} + +// NullAddrError is an error for a null address. +type NullAddrError struct{} + +func (n NullAddrError) Error() string { + return "NULL address" +} + +// stackIterator holds information +// required to iterate and walk the program +// stack. +type stackIterator struct { + pc, sp, bp uint64 + top bool + atend bool + frame Stackframe + dbp *Process + err error + + stackBarrierPC uint64 + stkbar []savedLR +} + +type savedLR struct { + ptr uint64 + val uint64 +} + +func newStackIterator(dbp *Process, pc, sp, bp uint64, stkbar []savedLR, stkbarPos int) *stackIterator { + stackBarrierFunc := dbp.goSymTable.LookupFunc(runtimeStackBarrier) // stack barriers were removed in Go 1.9 + var stackBarrierPC uint64 + if stackBarrierFunc != nil && stkbar != nil { + stackBarrierPC = stackBarrierFunc.Entry + fn := dbp.goSymTable.PCToFunc(pc) + if fn != nil && fn.Name == runtimeStackBarrier { + // We caught the goroutine as it's executing the stack barrier, we must + // determine whether or not g.stackPos has already been incremented or not. + if len(stkbar) > 0 && stkbar[stkbarPos].ptr < sp { + // runtime.stackBarrier has not incremented stkbarPos. + } else if stkbarPos > 0 && stkbar[stkbarPos-1].ptr < sp { + // runtime.stackBarrier has incremented stkbarPos. + stkbarPos-- + } else { + return &stackIterator{err: fmt.Errorf("failed to unwind through stackBarrier at SP %x", sp)} + } + } + stkbar = stkbar[stkbarPos:] + } + return &stackIterator{pc: pc, sp: sp, bp: bp, top: true, dbp: dbp, err: nil, atend: false, stackBarrierPC: stackBarrierPC, stkbar: stkbar} +} + +// Next points the iterator to the next stack frame. +func (it *stackIterator) Next() bool { + if it.err != nil || it.atend { + return false + } + it.frame, it.err = it.dbp.frameInfo(it.pc, it.sp, it.bp, it.top) + if it.err != nil { + if _, nofde := it.err.(*frame.NoFDEForPCError); nofde && !it.top { + it.frame = Stackframe{Current: Location{PC: it.pc, File: "?", Line: -1}, Call: Location{PC: it.pc, File: "?", Line: -1}, CFA: 0, Ret: 0} + it.atend = true + it.err = nil + return true + } + return false + } + + if it.frame.Ret <= 0 { + it.atend = true + return true + } + + if it.stkbar != nil && it.frame.Ret == it.stackBarrierPC && it.frame.addrret == it.stkbar[0].ptr { + // Skip stack barrier frames + it.frame.Ret = it.stkbar[0].val + it.stkbar = it.stkbar[1:] + } + + // Look for "top of stack" functions. + if it.frame.Current.Fn != nil && (it.frame.Current.Fn.Name == "runtime.goexit" || it.frame.Current.Fn.Name == "runtime.rt0_go" || it.frame.Current.Fn.Name == "runtime.mcall") { + it.atend = true + return true + } + + it.top = false + it.pc = it.frame.Ret + it.sp = uint64(it.frame.CFA) + it.bp, _ = readUintRaw(it.dbp.currentThread, uintptr(it.bp), int64(it.dbp.arch.PtrSize())) + return true +} + +// Frame returns the frame the iterator is pointing at. +func (it *stackIterator) Frame() Stackframe { + if it.err != nil { + panic(it.err) + } + return it.frame +} + +// Err returns the error encountered during stack iteration. +func (it *stackIterator) Err() error { + return it.err +} + +func (dbp *Process) frameInfo(pc, sp, bp uint64, top bool) (Stackframe, error) { + fde, err := dbp.frameEntries.FDEForPC(pc) + if _, nofde := err.(*frame.NoFDEForPCError); nofde { + if bp == 0 { + return Stackframe{}, err + } + // When no FDE is available attempt to use BP instead + retaddr := uintptr(int(bp) + dbp.arch.PtrSize()) + cfa := int64(retaddr) + int64(dbp.arch.PtrSize()) + return dbp.newStackframe(pc, cfa, retaddr, nil, top) + } + + spoffset, retoffset := fde.ReturnAddressOffset(pc) + cfa := int64(sp) + spoffset + + retaddr := uintptr(cfa + retoffset) + return dbp.newStackframe(pc, cfa, retaddr, fde, top) +} + +func (dbp *Process) newStackframe(pc uint64, cfa int64, retaddr uintptr, fde *frame.FrameDescriptionEntry, top bool) (Stackframe, error) { + if retaddr == 0 { + return Stackframe{}, NullAddrError{} + } + f, l, fn := dbp.PCToLine(pc) + ret, err := readUintRaw(dbp.currentThread, retaddr, int64(dbp.arch.PtrSize())) + if err != nil { + return Stackframe{}, err + } + r := Stackframe{Current: Location{PC: pc, File: f, Line: l, Fn: fn}, CFA: cfa, FDE: fde, Ret: ret, addrret: uint64(retaddr)} + if !top { + r.Call.File, r.Call.Line, r.Call.Fn = dbp.PCToLine(pc - 1) + r.Call.PC = r.Current.PC + } else { + r.Call = r.Current + } + return r, nil +} + +func (it *stackIterator) stacktrace(depth int) ([]Stackframe, error) { + if depth < 0 { + return nil, errors.New("negative maximum stack depth") + } + frames := make([]Stackframe, 0, depth+1) + for it.Next() { + frames = append(frames, it.Frame()) + if len(frames) >= depth+1 { + break + } + } + if err := it.Err(); err != nil { + return nil, err + } + return frames, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/syscall_windows.go b/vendor/github.com/derekparker/delve/pkg/proc/syscall_windows.go new file mode 100644 index 0000000..770a789 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/syscall_windows.go @@ -0,0 +1,112 @@ +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go + +package proc + +import ( + "syscall" +) + +type _NTSTATUS int32 + +type _CLIENT_ID struct { + UniqueProcess syscall.Handle + UniqueThread syscall.Handle +} + +type _THREAD_BASIC_INFORMATION struct { + ExitStatus _NTSTATUS + TebBaseAddress uintptr + ClientId _CLIENT_ID + AffinityMask uintptr + Priority int32 + BasePriority int32 +} + +type _CREATE_PROCESS_DEBUG_INFO struct { + File syscall.Handle + Process syscall.Handle + Thread syscall.Handle + BaseOfImage uintptr + DebugInfoFileOffset uint32 + DebugInfoSize uint32 + ThreadLocalBase uintptr + StartAddress uintptr + ImageName uintptr + Unicode uint16 +} + +type _CREATE_THREAD_DEBUG_INFO struct { + Thread syscall.Handle + ThreadLocalBase uintptr + StartAddress uintptr +} + +type _EXIT_PROCESS_DEBUG_INFO struct { + ExitCode uint32 +} + +type _LOAD_DLL_DEBUG_INFO struct { + File syscall.Handle + BaseOfDll uintptr + DebugInfoFileOffset uint32 + DebugInfoSize uint32 + ImageName uintptr + Unicode uint16 +} + +type _EXCEPTION_DEBUG_INFO struct { + ExceptionRecord _EXCEPTION_RECORD + FirstChance uint32 +} + +type _EXCEPTION_RECORD struct { + ExceptionCode uint32 + ExceptionFlags uint32 + ExceptionRecord *_EXCEPTION_RECORD + ExceptionAddress uintptr + NumberParameters uint32 + ExceptionInformation [_EXCEPTION_MAXIMUM_PARAMETERS]uintptr +} + +const ( + _ThreadBasicInformation = 0 + + _DBG_CONTINUE = 0x00010002 + _DBG_EXCEPTION_NOT_HANDLED = 0x80010001 + + _EXCEPTION_DEBUG_EVENT = 1 + _CREATE_THREAD_DEBUG_EVENT = 2 + _CREATE_PROCESS_DEBUG_EVENT = 3 + _EXIT_THREAD_DEBUG_EVENT = 4 + _EXIT_PROCESS_DEBUG_EVENT = 5 + _LOAD_DLL_DEBUG_EVENT = 6 + _UNLOAD_DLL_DEBUG_EVENT = 7 + _OUTPUT_DEBUG_STRING_EVENT = 8 + _RIP_EVENT = 9 + + // DEBUG_ONLY_THIS_PROCESS tracks https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx + _DEBUG_ONLY_THIS_PROCESS = 0x00000002 + + _EXCEPTION_BREAKPOINT = 0x80000003 + _EXCEPTION_SINGLE_STEP = 0x80000004 + + _EXCEPTION_MAXIMUM_PARAMETERS = 15 +) + +func _NT_SUCCESS(x _NTSTATUS) bool { + return x >= 0 +} + +//sys _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread +//sys _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.GetThreadContext +//sys _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.SetThreadContext +//sys _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.SuspendThread +//sys _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.ResumeThread +//sys _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) = kernel32.ContinueDebugEvent +//sys _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) = kernel32.WriteProcessMemory +//sys _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) = kernel32.ReadProcessMemory +//sys _DebugBreakProcess(process syscall.Handle) (err error) = kernel32.DebugBreakProcess +//sys _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) = kernel32.WaitForDebugEvent +//sys _DebugActiveProcess(processid uint32) (err error) = kernel32.DebugActiveProcess +//sys _DebugActiveProcessStop(processid uint32) (err error) = kernel32.DebugActiveProcessStop +//sys _QueryFullProcessImageName(process syscall.Handle, flags uint32, exename *uint16, size *uint32) (err error) = kernel32.QueryFullProcessImageNameW diff --git a/vendor/github.com/derekparker/delve/pkg/proc/syscall_windows_amd64.go b/vendor/github.com/derekparker/delve/pkg/proc/syscall_windows_amd64.go new file mode 100644 index 0000000..1ce592e --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/syscall_windows_amd64.go @@ -0,0 +1,114 @@ +package proc + +import "unsafe" + +const ( + _CONTEXT_AMD64 = 0x100000 + _CONTEXT_CONTROL = (_CONTEXT_AMD64 | 0x1) + _CONTEXT_INTEGER = (_CONTEXT_AMD64 | 0x2) + _CONTEXT_SEGMENTS = (_CONTEXT_AMD64 | 0x4) + _CONTEXT_FLOATING_POINT = (_CONTEXT_AMD64 | 0x8) + _CONTEXT_DEBUG_REGISTERS = (_CONTEXT_AMD64 | 0x10) + _CONTEXT_FULL = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_FLOATING_POINT) + _CONTEXT_ALL = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_SEGMENTS | _CONTEXT_FLOATING_POINT | _CONTEXT_DEBUG_REGISTERS) + _CONTEXT_EXCEPTION_ACTIVE = 0x8000000 + _CONTEXT_SERVICE_ACTIVE = 0x10000000 + _CONTEXT_EXCEPTION_REQUEST = 0x40000000 + _CONTEXT_EXCEPTION_REPORTING = 0x80000000 +) + +type _M128A struct { + Low uint64 + High int64 +} + +type _XMM_SAVE_AREA32 struct { + ControlWord uint16 + StatusWord uint16 + TagWord byte + Reserved1 byte + ErrorOpcode uint16 + ErrorOffset uint32 + ErrorSelector uint16 + Reserved2 uint16 + DataOffset uint32 + DataSelector uint16 + Reserved3 uint16 + MxCsr uint32 + MxCsr_Mask uint32 + FloatRegisters [8]_M128A + XmmRegisters [256]byte + Reserved4 [96]byte +} + +type _CONTEXT struct { + P1Home uint64 + P2Home uint64 + P3Home uint64 + P4Home uint64 + P5Home uint64 + P6Home uint64 + + ContextFlags uint32 + MxCsr uint32 + + SegCs uint16 + SegDs uint16 + SegEs uint16 + SegFs uint16 + SegGs uint16 + SegSs uint16 + EFlags uint32 + + Dr0 uint64 + Dr1 uint64 + Dr2 uint64 + Dr3 uint64 + Dr6 uint64 + Dr7 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 uint64 + + FltSave _XMM_SAVE_AREA32 + + VectorRegister [26]_M128A + VectorControl uint64 + + DebugControl uint64 + LastBranchToRip uint64 + LastBranchFromRip uint64 + LastExceptionToRip uint64 + LastExceptionFromRip uint64 +} + +// newCONTEXT allocates Windows CONTEXT structure aligned to 16 bytes. +func newCONTEXT() *_CONTEXT { + var c *_CONTEXT + buf := make([]byte, unsafe.Sizeof(*c)+15) + return (*_CONTEXT)(unsafe.Pointer((uintptr(unsafe.Pointer(&buf[15]))) &^ 15)) +} + +type _DEBUG_EVENT struct { + DebugEventCode uint32 + ProcessId uint32 + ThreadId uint32 + _ uint32 // to align Union properly + U [160]byte +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/threads.go b/vendor/github.com/derekparker/delve/pkg/proc/threads.go new file mode 100644 index 0000000..4e44efe --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/threads.go @@ -0,0 +1,510 @@ +package proc + +import ( + "debug/gosym" + "encoding/binary" + "errors" + "fmt" + "go/ast" + "path/filepath" + "reflect" + "runtime" + "strings" + + "golang.org/x/debug/dwarf" +) + +// Thread represents a single thread in the traced process +// ID represents the thread id or port, Process holds a reference to the +// Process struct that contains info on the process as +// a whole, and Status represents the last result of a `wait` call +// on this thread. +type Thread struct { + ID int // Thread ID or mach port + Status *WaitStatus // Status returned from last wait call + CurrentBreakpoint *Breakpoint // Breakpoint thread is currently stopped at + BreakpointConditionMet bool // Output of evaluating the breakpoint's condition + BreakpointConditionError error // Error evaluating the breakpoint's condition + + dbp *Process + singleStepping bool + running bool + os *OSSpecificDetails +} + +// Location represents the location of a thread. +// Holds information on the current instruction +// address, the source file:line, and the function. +type Location struct { + PC uint64 + File string + Line int + Fn *gosym.Func +} + +// Continue the execution of this thread. +// +// If we are currently at a breakpoint, we'll clear it +// first and then resume execution. Thread will continue until +// it hits a breakpoint or is signaled. +func (thread *Thread) Continue() error { + pc, err := thread.PC() + if err != nil { + return err + } + // Check whether we are stopped at a breakpoint, and + // if so, single step over it before continuing. + if _, ok := thread.dbp.FindBreakpoint(pc); ok { + if err := thread.StepInstruction(); err != nil { + return err + } + } + return thread.resume() +} + +// StepInstruction steps a single instruction. +// +// Executes exactly one instruction and then returns. +// If the thread is at a breakpoint, we first clear it, +// execute the instruction, and then replace the breakpoint. +// Otherwise we simply execute the next instruction. +func (thread *Thread) StepInstruction() (err error) { + thread.running = true + thread.singleStepping = true + defer func() { + thread.singleStepping = false + thread.running = false + }() + pc, err := thread.PC() + if err != nil { + return err + } + + bp, ok := thread.dbp.FindBreakpoint(pc) + if ok { + // Clear the breakpoint so that we can continue execution. + _, err = bp.Clear(thread) + if err != nil { + return err + } + + // Restore breakpoint now that we have passed it. + defer func() { + err = thread.dbp.writeSoftwareBreakpoint(thread, bp.Addr) + }() + } + + err = thread.singleStep() + if err != nil { + if _, exited := err.(ProcessExitedError); exited { + return err + } + return fmt.Errorf("step failed: %s", err.Error()) + } + return nil +} + +// Location returns the threads location, including the file:line +// of the corresponding source code, the function we're in +// and the current instruction address. +func (thread *Thread) Location() (*Location, error) { + pc, err := thread.PC() + if err != nil { + return nil, err + } + f, l, fn := thread.dbp.PCToLine(pc) + return &Location{PC: pc, File: f, Line: l, Fn: fn}, nil +} + +// ThreadBlockedError is returned when the thread +// is blocked in the scheduler. +type ThreadBlockedError struct{} + +func (tbe ThreadBlockedError) Error() string { + return "" +} + +// returns topmost frame of g or thread if g is nil +func topframe(g *G, thread *Thread) (Stackframe, error) { + var frames []Stackframe + var err error + + if g == nil { + if thread.blocked() { + return Stackframe{}, ThreadBlockedError{} + } + frames, err = thread.Stacktrace(0) + } else { + frames, err = g.Stacktrace(0) + } + if err != nil { + return Stackframe{}, err + } + if len(frames) < 1 { + return Stackframe{}, errors.New("empty stack trace") + } + return frames[0], nil +} + +// Set breakpoints at every line, and the return address. Also look for +// a deferred function and set a breakpoint there too. +// If stepInto is true it will also set breakpoints inside all +// functions called on the current source line, for non-absolute CALLs +// a breakpoint of kind StepBreakpoint is set on the CALL instruction, +// Continue will take care of setting a breakpoint to the destination +// once the CALL is reached. +func (dbp *Process) next(stepInto bool) error { + topframe, err := topframe(dbp.selectedGoroutine, dbp.currentThread) + if err != nil { + return err + } + + success := false + defer func() { + if !success { + dbp.ClearInternalBreakpoints() + } + }() + + csource := filepath.Ext(topframe.Current.File) != ".go" + thread := dbp.currentThread + currentGoroutine := false + if dbp.selectedGoroutine != nil && dbp.selectedGoroutine.thread != nil { + thread = dbp.selectedGoroutine.thread + currentGoroutine = true + } + + text, err := thread.Disassemble(topframe.FDE.Begin(), topframe.FDE.End(), currentGoroutine) + if err != nil && stepInto { + return err + } + + cond := sameGoroutineCondition(dbp.selectedGoroutine) + + if stepInto { + for _, instr := range text { + if instr.Loc.File != topframe.Current.File || instr.Loc.Line != topframe.Current.Line || !instr.IsCall() { + continue + } + + if instr.DestLoc != nil && instr.DestLoc.Fn != nil { + if err := dbp.setStepIntoBreakpoint([]AsmInstruction{instr}, cond); err != nil { + return err + } + } else { + // Non-absolute call instruction, set a StepBreakpoint here + if _, err := dbp.SetBreakpoint(instr.Loc.PC, StepBreakpoint, cond); err != nil { + if _, ok := err.(BreakpointExistsError); !ok { + return err + } + } + } + } + } + + if !csource { + deferreturns := []uint64{} + + // Find all runtime.deferreturn locations in the function + // See documentation of Breakpoint.DeferCond for why this is necessary + for _, instr := range text { + if instr.IsCall() && instr.DestLoc != nil && instr.DestLoc.Fn != nil && instr.DestLoc.Fn.Name == "runtime.deferreturn" { + deferreturns = append(deferreturns, instr.Loc.PC) + } + } + + // Set breakpoint on the most recently deferred function (if any) + var deferpc uint64 = 0 + if dbp.selectedGoroutine != nil { + deferPCEntry := dbp.selectedGoroutine.DeferPC() + if deferPCEntry != 0 { + _, _, deferfn := dbp.goSymTable.PCToLine(deferPCEntry) + var err error + deferpc, err = dbp.FirstPCAfterPrologue(deferfn, false) + if err != nil { + return err + } + } + } + if deferpc != 0 && deferpc != topframe.Current.PC { + bp, err := dbp.SetBreakpoint(deferpc, NextDeferBreakpoint, cond) + if err != nil { + if _, ok := err.(BreakpointExistsError); !ok { + return err + } + } + if bp != nil { + bp.DeferReturns = deferreturns + } + } + } + + // Add breakpoints on all the lines in the current function + pcs, err := dbp.lineInfo.AllPCsBetween(topframe.FDE.Begin(), topframe.FDE.End()-1, topframe.Current.File) + if err != nil { + return err + } + + if !csource { + var covered bool + for i := range pcs { + if topframe.FDE.Cover(pcs[i]) { + covered = true + break + } + } + + if !covered { + fn := dbp.goSymTable.PCToFunc(topframe.Ret) + if dbp.selectedGoroutine != nil && fn != nil && fn.Name == "runtime.goexit" { + return nil + } + } + } + + // Add a breakpoint on the return address for the current frame + pcs = append(pcs, topframe.Ret) + success = true + return dbp.setInternalBreakpoints(topframe.Current.PC, pcs, NextBreakpoint, cond) +} + +func (dbp *Process) setStepIntoBreakpoint(text []AsmInstruction, cond ast.Expr) error { + if len(text) <= 0 { + return nil + } + + instr := text[0] + + if instr.DestLoc == nil || instr.DestLoc.Fn == nil { + return nil + } + + fn := instr.DestLoc.Fn + + // Ensure PC and Entry match, otherwise StepInto is likely to set + // its breakpoint before DestLoc.PC and hence run too far ahead. + // Calls to runtime.duffzero and duffcopy have this problem. + if fn.Entry != instr.DestLoc.PC { + return nil + } + + // Skip unexported runtime functions + if strings.HasPrefix(fn.Name, "runtime.") && !isExportedRuntime(fn.Name) { + return nil + } + + //TODO(aarzilli): if we want to let users hide functions + // or entire packages from being stepped into with 'step' + // those extra checks should be done here. + + // Set a breakpoint after the function's prologue + pc, _ := dbp.FirstPCAfterPrologue(fn, false) + if _, err := dbp.SetBreakpoint(pc, NextBreakpoint, cond); err != nil { + if _, ok := err.(BreakpointExistsError); !ok { + return err + } + } + + return nil +} + +// setInternalBreakpoints sets a breakpoint to all addresses specified in pcs +// skipping over curpc and curpc-1 +func (dbp *Process) setInternalBreakpoints(curpc uint64, pcs []uint64, kind BreakpointKind, cond ast.Expr) error { + for i := range pcs { + if pcs[i] == curpc || pcs[i] == curpc-1 { + continue + } + if _, err := dbp.SetBreakpoint(pcs[i], kind, cond); err != nil { + if _, ok := err.(BreakpointExistsError); !ok { + dbp.ClearInternalBreakpoints() + return err + } + } + } + return nil +} + +// SetPC sets the PC for this thread. +func (thread *Thread) SetPC(pc uint64) error { + regs, err := thread.Registers(false) + if err != nil { + return err + } + return regs.SetPC(thread, pc) +} + +func (thread *Thread) getGVariable() (*Variable, error) { + regs, err := thread.Registers(false) + if err != nil { + return nil, err + } + + if thread.dbp.arch.GStructOffset() == 0 { + // GetG was called through SwitchThread / updateThreadList during initialization + // thread.dbp.arch isn't setup yet (it needs a current thread to read global variables from) + return nil, fmt.Errorf("g struct offset not initialized") + } + + gaddrbs, err := thread.readMemory(uintptr(regs.TLS()+thread.dbp.arch.GStructOffset()), thread.dbp.arch.PtrSize()) + if err != nil { + return nil, err + } + gaddr := uintptr(binary.LittleEndian.Uint64(gaddrbs)) + + // On Windows, the value at TLS()+GStructOffset() is a + // pointer to the G struct. + needsDeref := runtime.GOOS == "windows" + + return thread.newGVariable(gaddr, needsDeref) +} + +func (thread *Thread) newGVariable(gaddr uintptr, deref bool) (*Variable, error) { + typ, err := thread.dbp.findType("runtime.g") + if err != nil { + return nil, err + } + + name := "" + + if deref { + typ = &dwarf.PtrType{dwarf.CommonType{int64(thread.dbp.arch.PtrSize()), "", reflect.Ptr, 0}, typ} + } else { + name = "runtime.curg" + } + + return thread.newVariable(name, gaddr, typ), nil +} + +// GetG returns information on the G (goroutine) that is executing on this thread. +// +// The G structure for a thread is stored in thread local storage. Here we simply +// calculate the address and read and parse the G struct. +// +// We cannot simply use the allg linked list in order to find the M that represents +// the given OS thread and follow its G pointer because on Darwin mach ports are not +// universal, so our port for this thread would not map to the `id` attribute of the M +// structure. Also, when linked against libc, Go prefers the libc version of clone as +// opposed to the runtime version. This has the consequence of not setting M.id for +// any thread, regardless of OS. +// +// In order to get around all this craziness, we read the address of the G structure for +// the current thread from the thread local storage area. +func (thread *Thread) GetG() (g *G, err error) { + gaddr, err := thread.getGVariable() + if err != nil { + return nil, err + } + + g, err = gaddr.parseG() + if err == nil { + g.thread = thread + if loc, err := thread.Location(); err == nil { + g.CurrentLoc = *loc + } + } + return +} + +// Stopped returns whether the thread is stopped at +// the operating system level. Actual implementation +// is OS dependant, look in OS thread file. +func (thread *Thread) Stopped() bool { + return thread.stopped() +} + +// Halt stops this thread from executing. Actual +// implementation is OS dependant. Look in OS +// thread file. +func (thread *Thread) Halt() (err error) { + defer func() { + if err == nil { + thread.running = false + } + }() + if thread.Stopped() { + return + } + err = thread.halt() + return +} + +// Scope returns the current EvalScope for this thread. +func (thread *Thread) Scope() (*EvalScope, error) { + locations, err := thread.Stacktrace(0) + if err != nil { + return nil, err + } + if len(locations) < 1 { + return nil, errors.New("could not decode first frame") + } + return locations[0].Scope(thread), nil +} + +// SetCurrentBreakpoint sets the current breakpoint that this +// thread is stopped at as CurrentBreakpoint on the thread struct. +func (thread *Thread) SetCurrentBreakpoint() error { + thread.CurrentBreakpoint = nil + pc, err := thread.PC() + if err != nil { + return err + } + if bp, ok := thread.dbp.FindBreakpoint(pc); ok { + thread.CurrentBreakpoint = bp + if err = thread.SetPC(bp.Addr); err != nil { + return err + } + thread.BreakpointConditionMet, thread.BreakpointConditionError = bp.checkCondition(thread) + if thread.onTriggeredBreakpoint() { + if g, err := thread.GetG(); err == nil { + thread.CurrentBreakpoint.HitCount[g.ID]++ + } + thread.CurrentBreakpoint.TotalHitCount++ + } + } + return nil +} + +func (thread *Thread) clearBreakpointState() { + thread.CurrentBreakpoint = nil + thread.BreakpointConditionMet = false + thread.BreakpointConditionError = nil +} + +func (thread *Thread) onTriggeredBreakpoint() bool { + return (thread.CurrentBreakpoint != nil) && thread.BreakpointConditionMet +} + +func (thread *Thread) onTriggeredInternalBreakpoint() bool { + return thread.onTriggeredBreakpoint() && thread.CurrentBreakpoint.Internal() +} + +func (thread *Thread) onRuntimeBreakpoint() bool { + loc, err := thread.Location() + if err != nil { + return false + } + return loc.Fn != nil && loc.Fn.Name == "runtime.breakpoint" +} + +// onNextGorutine returns true if this thread is on the goroutine requested by the current 'next' command +func (thread *Thread) onNextGoroutine() (bool, error) { + var bp *Breakpoint + for i := range thread.dbp.breakpoints { + if thread.dbp.breakpoints[i].Internal() { + bp = thread.dbp.breakpoints[i] + break + } + } + if bp == nil { + return false, nil + } + if bp.Kind == NextDeferBreakpoint { + // we just want to check the condition on the goroutine id here + bp.Kind = NextBreakpoint + defer func() { + bp.Kind = NextDeferBreakpoint + }() + } + return bp.checkCondition(thread) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.c b/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.c new file mode 100644 index 0000000..88a92f4 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.c @@ -0,0 +1,177 @@ +#include "threads_darwin.h" + +int +write_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) { + kern_return_t kret; + vm_region_submap_short_info_data_64_t info; + mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + mach_vm_size_t l = len; + mach_port_t objname; + + if (len == 1) l = 2; + kret = mach_vm_region((vm_map_t)task, &(mach_vm_address_t){addr}, (mach_vm_size_t*)&l, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &objname); + if (kret != KERN_SUCCESS) return -1; + + // Set permissions to enable writting to this memory location + kret = mach_vm_protect(task, addr, len, FALSE, VM_PROT_WRITE|VM_PROT_COPY|VM_PROT_READ); + if (kret != KERN_SUCCESS) return -1; + + kret = mach_vm_write((vm_map_t)task, addr, (vm_offset_t)d, len); + if (kret != KERN_SUCCESS) return -1; + + // Restore virtual memory permissions + kret = mach_vm_protect(task, addr, len, FALSE, info.protection); + if (kret != KERN_SUCCESS) return -1; + + return 0; +} + +int +read_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) { + kern_return_t kret; + pointer_t data; + mach_msg_type_number_t count; + + kret = mach_vm_read((vm_map_t)task, addr, len, &data, &count); + if (kret != KERN_SUCCESS) return -1; + memcpy(d, (void *)data, len); + + kret = vm_deallocate(task, data, len); + if (kret != KERN_SUCCESS) return -1; + + return count; +} + +kern_return_t +get_registers(mach_port_name_t task, x86_thread_state64_t *state) { + kern_return_t kret; + mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT; + // TODO(dp) - possible memory leak - vm_deallocate state + return thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)state, &stateCount); +} + +kern_return_t +get_fpu_registers(mach_port_name_t task, x86_float_state64_t *state) { + kern_return_t kret; + mach_msg_type_number_t stateCount = x86_FLOAT_STATE64_COUNT; + return thread_get_state(task, x86_FLOAT_STATE64, (thread_state_t)state, &stateCount); +} + +kern_return_t +get_identity(mach_port_name_t task, thread_identifier_info_data_t *idinfo) { + mach_msg_type_number_t idinfoCount = THREAD_IDENTIFIER_INFO_COUNT; + return thread_info(task, THREAD_IDENTIFIER_INFO, (thread_info_t)idinfo, &idinfoCount); +} + +kern_return_t +set_registers(mach_port_name_t task, x86_thread_state64_t *state) { + mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT; + return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)state, stateCount); +} + +kern_return_t +set_pc(thread_act_t task, uint64_t pc) { + kern_return_t kret; + x86_thread_state64_t state; + mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT; + + kret = thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)&state, &stateCount); + if (kret != KERN_SUCCESS) return kret; + state.__rip = pc; + + return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)&state, stateCount); +} + +kern_return_t +single_step(thread_act_t thread) { + kern_return_t kret; + x86_thread_state64_t regs; + mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; + + kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, &count); + if (kret != KERN_SUCCESS) return kret; + + // Set trap bit in rflags + regs.__rflags |= 0x100UL; + + kret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, count); + if (kret != KERN_SUCCESS) return kret; + + return resume_thread(thread); +} + +kern_return_t +resume_thread(thread_act_t thread) { + kern_return_t kret; + struct thread_basic_info info; + unsigned int info_count = THREAD_BASIC_INFO_COUNT; + + kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count); + if (kret != KERN_SUCCESS) return kret; + + for (int i = 0; i < info.suspend_count; i++) { + kret = thread_resume(thread); + if (kret != KERN_SUCCESS) return kret; + } + return KERN_SUCCESS; +} + +kern_return_t +clear_trap_flag(thread_act_t thread) { + kern_return_t kret; + x86_thread_state64_t regs; + mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; + + kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, &count); + if (kret != KERN_SUCCESS) return kret; + + // Clear trap bit in rflags + regs.__rflags ^= 0x100UL; + + return thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, count); +} + +int +thread_blocked(thread_act_t thread) { + kern_return_t kret; + struct thread_basic_info info; + unsigned int info_count = THREAD_BASIC_INFO_COUNT; + + kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count); + if (kret != KERN_SUCCESS) return -1; + + return info.suspend_count; +} + +int +num_running_threads(task_t task) { + kern_return_t kret; + thread_act_array_t list; + mach_msg_type_number_t count; + int i, n = 0; + + kret = task_threads(task, &list, &count); + if (kret != KERN_SUCCESS) { + return -kret; + } + + for (i = 0; i < count; ++i) { + thread_act_t thread = list[i]; + struct thread_basic_info info; + unsigned int info_count = THREAD_BASIC_INFO_COUNT; + + kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count); + + if (kret == KERN_SUCCESS) { + if (info.suspend_count == 0) { + ++n; + } else { + } + } + } + + kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); + if (kret != KERN_SUCCESS) return -kret; + + return n; +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.go b/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.go new file mode 100644 index 0000000..71c025b --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.go @@ -0,0 +1,137 @@ +package proc + +// #include "threads_darwin.h" +// #include "proc_darwin.h" +import "C" +import ( + "fmt" + "unsafe" + + sys "golang.org/x/sys/unix" +) + +// WaitStatus is a synonym for the platform-specific WaitStatus +type WaitStatus sys.WaitStatus + +// OSSpecificDetails holds information specific to the OSX/Darwin +// operating system / kernel. +type OSSpecificDetails struct { + threadAct C.thread_act_t + registers C.x86_thread_state64_t + exists bool +} + +// ErrContinueThread is the error returned when a thread could not +// be continued. +var ErrContinueThread = fmt.Errorf("could not continue thread") + +func (t *Thread) halt() (err error) { + kret := C.thread_suspend(t.os.threadAct) + if kret != C.KERN_SUCCESS { + errStr := C.GoString(C.mach_error_string(C.mach_error_t(kret))) + // check that the thread still exists before complaining + err2 := t.dbp.updateThreadList() + if err2 != nil { + err = fmt.Errorf("could not suspend thread %d %s (additionally could not update thread list: %v)", t.ID, errStr, err2) + return + } + + if _, ok := t.dbp.threads[t.ID]; ok { + err = fmt.Errorf("could not suspend thread %d %s", t.ID, errStr) + return + } + } + return +} + +func (t *Thread) singleStep() error { + kret := C.single_step(t.os.threadAct) + if kret != C.KERN_SUCCESS { + return fmt.Errorf("could not single step") + } + for { + twthread, err := t.dbp.trapWait(t.dbp.pid) + if err != nil { + return err + } + if twthread.ID == t.ID { + break + } + } + + kret = C.clear_trap_flag(t.os.threadAct) + if kret != C.KERN_SUCCESS { + return fmt.Errorf("could not clear CPU trap flag") + } + return nil +} + +func (t *Thread) resume() error { + t.running = true + // TODO(dp) set flag for ptrace stops + var err error + t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.pid, 0) }) + if err == nil { + return nil + } + kret := C.resume_thread(t.os.threadAct) + if kret != C.KERN_SUCCESS { + return ErrContinueThread + } + return nil +} + +func (t *Thread) blocked() bool { + // TODO(dp) cache the func pc to remove this lookup + pc, err := t.PC() + if err != nil { + return false + } + fn := t.dbp.goSymTable.PCToFunc(pc) + if fn == nil { + return false + } + switch fn.Name { + case "runtime.kevent", "runtime.mach_semaphore_wait", "runtime.usleep": + return true + default: + return false + } +} + +func (t *Thread) stopped() bool { + return C.thread_blocked(t.os.threadAct) > C.int(0) +} + +func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { + if len(data) == 0 { + return 0, nil + } + var ( + vmData = unsafe.Pointer(&data[0]) + vmAddr = C.mach_vm_address_t(addr) + length = C.mach_msg_type_number_t(len(data)) + ) + if ret := C.write_memory(t.dbp.os.task, vmAddr, vmData, length); ret < 0 { + return 0, fmt.Errorf("could not write memory") + } + return len(data), nil +} + +func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { + if size == 0 { + return nil, nil + } + var ( + buf = make([]byte, size) + vmData = unsafe.Pointer(&buf[0]) + vmAddr = C.mach_vm_address_t(addr) + length = C.mach_msg_type_number_t(size) + ) + + ret := C.read_memory(t.dbp.os.task, vmAddr, vmData, length) + if ret < 0 { + return nil, fmt.Errorf("could not read memory") + } + return buf, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.h b/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.h new file mode 100644 index 0000000..75a82b8 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.h @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +int +write_memory(task_t, mach_vm_address_t, void *, mach_msg_type_number_t); + +int +read_memory(task_t, mach_vm_address_t, void *, mach_msg_type_number_t); + +kern_return_t +get_registers(mach_port_name_t, x86_thread_state64_t*); + +kern_return_t +get_fpu_registers(mach_port_name_t, x86_float_state64_t *); + +kern_return_t +set_pc(thread_act_t, uint64_t); + +kern_return_t +single_step(thread_act_t); + +kern_return_t +clear_trap_flag(thread_act_t); + +kern_return_t +resume_thread(thread_act_t); + +kern_return_t +set_registers(mach_port_name_t, x86_thread_state64_t*); + +kern_return_t +get_identity(mach_port_name_t, thread_identifier_info_data_t *); + +int +thread_blocked(thread_act_t thread); + +int +num_running_threads(task_t task); diff --git a/vendor/github.com/derekparker/delve/pkg/proc/threads_linux.go b/vendor/github.com/derekparker/delve/pkg/proc/threads_linux.go new file mode 100644 index 0000000..8592a2c --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/threads_linux.go @@ -0,0 +1,108 @@ +package proc + +import ( + "fmt" + + sys "golang.org/x/sys/unix" +) + +type WaitStatus sys.WaitStatus + +// OSSpecificDetails hold Linux specific +// process details. +type OSSpecificDetails struct { + registers sys.PtraceRegs +} + +func (t *Thread) halt() (err error) { + err = sys.Tgkill(t.dbp.pid, t.ID, sys.SIGSTOP) + if err != nil { + err = fmt.Errorf("halt err %s on thread %d", err, t.ID) + return + } + _, _, err = t.dbp.wait(t.ID, 0) + if err != nil { + err = fmt.Errorf("wait err %s on thread %d", err, t.ID) + return + } + return +} + +func (t *Thread) stopped() bool { + state := status(t.ID, t.dbp.os.comm) + return state == StatusTraceStop || state == StatusTraceStopT +} + +func (t *Thread) resume() error { + return t.resumeWithSig(0) +} + +func (t *Thread) resumeWithSig(sig int) (err error) { + t.running = true + t.dbp.execPtraceFunc(func() { err = PtraceCont(t.ID, sig) }) + return +} + +func (t *Thread) singleStep() (err error) { + for { + t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.ID) }) + if err != nil { + return err + } + wpid, status, err := t.dbp.waitFast(t.ID) + if err != nil { + return err + } + if (status == nil || status.Exited()) && wpid == t.dbp.pid { + t.dbp.postExit() + rs := 0 + if status != nil { + rs = status.ExitStatus() + } + return ProcessExitedError{Pid: t.dbp.pid, Status: rs} + } + if wpid == t.ID && status.StopSignal() == sys.SIGTRAP { + return nil + } + } +} + +func (t *Thread) blocked() bool { + pc, _ := t.PC() + fn := t.dbp.goSymTable.PCToFunc(pc) + if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) { + return true + } + return false +} + +func (t *Thread) saveRegisters() (Registers, error) { + var err error + t.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(t.ID, &t.os.registers) }) + if err != nil { + return nil, fmt.Errorf("could not save register contents") + } + return &Regs{&t.os.registers, nil}, nil +} + +func (t *Thread) restoreRegisters() (err error) { + t.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(t.ID, &t.os.registers) }) + return +} + +func (t *Thread) writeMemory(addr uintptr, data []byte) (written int, err error) { + if len(data) == 0 { + return + } + t.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(t.ID, addr, data) }) + return +} + +func (t *Thread) readMemory(addr uintptr, size int) (data []byte, err error) { + if size == 0 { + return + } + data = make([]byte, size) + t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) }) + return +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/threads_windows.go b/vendor/github.com/derekparker/delve/pkg/proc/threads_windows.go new file mode 100644 index 0000000..536a411 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/threads_windows.go @@ -0,0 +1,151 @@ +package proc + +import ( + "syscall" + + sys "golang.org/x/sys/windows" +) + +// WaitStatus is a synonym for the platform-specific WaitStatus +type WaitStatus sys.WaitStatus + +// OSSpecificDetails holds information specific to the Windows +// operating system / kernel. +type OSSpecificDetails struct { + hThread syscall.Handle +} + +func (t *Thread) halt() (err error) { + // Ignore the request to halt. On Windows, all threads are halted + // on return from WaitForDebugEvent. + return nil + + // TODO - This may not be correct in all usages of dbp.Halt. There + // are some callers who use dbp.Halt() to stop the process when it is not + // already broken on a debug event. +} + +func (t *Thread) singleStep() error { + context := newCONTEXT() + context.ContextFlags = _CONTEXT_ALL + + // Set the processor TRAP flag + err := _GetThreadContext(t.os.hThread, context) + if err != nil { + return err + } + + context.EFlags |= 0x100 + + err = _SetThreadContext(t.os.hThread, context) + if err != nil { + return err + } + + _, err = _ResumeThread(t.os.hThread) + if err != nil { + return err + } + + for { + var tid, exitCode int + t.dbp.execPtraceFunc(func() { + tid, exitCode, err = t.dbp.waitForDebugEvent(waitBlocking | waitSuspendNewThreads) + }) + if err != nil { + return err + } + if tid == 0 { + t.dbp.postExit() + return ProcessExitedError{Pid: t.dbp.pid, Status: exitCode} + } + + if t.dbp.os.breakThread == t.ID { + break + } + + t.dbp.execPtraceFunc(func() { + err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.dbp.os.breakThread), _DBG_CONTINUE) + }) + } + + _, err = _SuspendThread(t.os.hThread) + if err != nil { + return err + } + + t.dbp.execPtraceFunc(func() { + err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE) + }) + if err != nil { + return err + } + + // Unset the processor TRAP flag + err = _GetThreadContext(t.os.hThread, context) + if err != nil { + return err + } + + context.EFlags &= ^uint32(0x100) + + return _SetThreadContext(t.os.hThread, context) +} + +func (t *Thread) resume() error { + t.running = true + var err error + t.dbp.execPtraceFunc(func() { + //TODO: Note that we are ignoring the thread we were asked to continue and are continuing the + //thread that we last broke on. + err = _ContinueDebugEvent(uint32(t.dbp.pid), uint32(t.ID), _DBG_CONTINUE) + }) + return err +} + +func (t *Thread) blocked() bool { + // TODO: Probably incorrect - what are the runtime functions that + // indicate blocking on Windows? + pc, err := t.PC() + if err != nil { + return false + } + fn := t.dbp.goSymTable.PCToFunc(pc) + if fn == nil { + return false + } + switch fn.Name { + case "runtime.kevent", "runtime.usleep": + return true + default: + return false + } +} + +func (t *Thread) stopped() bool { + // TODO: We are assuming that threads are always stopped + // during command execution. + return true +} + +func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { + var count uintptr + err := _WriteProcessMemory(t.dbp.os.hProcess, addr, &data[0], uintptr(len(data)), &count) + if err != nil { + return 0, err + } + return int(count), nil +} + +func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { + if size == 0 { + return nil, nil + } + var count uintptr + buf := make([]byte, size) + err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(size), &count) + if err != nil { + return nil, err + } + return buf[:count], nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/types.go b/vendor/github.com/derekparker/delve/pkg/proc/types.go new file mode 100644 index 0000000..65b8b38 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/types.go @@ -0,0 +1,755 @@ +package proc + +import ( + "bytes" + "errors" + "fmt" + "go/ast" + "go/constant" + "go/token" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "unsafe" + + "github.com/derekparker/delve/pkg/dwarf/reader" + + "golang.org/x/debug/dwarf" +) + +// The kind field in runtime._type is a reflect.Kind value plus +// some extra flags defined here. +// See equivalent declaration in $GOROOT/src/reflect/type.go +const ( + kindDirectIface = 1 << 5 + kindGCProg = 1 << 6 // Type.gc points to GC program + kindNoPointers = 1 << 7 + kindMask = (1 << 5) - 1 +) + +// Value of tflag field in runtime._type. +// See $GOROOT/reflect/type.go for a description of these flags. +const ( + tflagUncommon = 1 << 0 + tflagExtraStar = 1 << 1 + tflagNamed = 1 << 2 +) + +// Do not call this function directly it isn't able to deal correctly with package paths +func (dbp *Process) findType(name string) (dwarf.Type, error) { + off, found := dbp.types[name] + if !found { + return nil, reader.TypeNotFoundErr + } + return dbp.dwarf.Type(off) +} + +func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type { + return &dwarf.PtrType{dwarf.CommonType{int64(dbp.arch.PtrSize()), "*" + typ.Common().Name, reflect.Ptr, 0}, typ} +} + +func (dbp *Process) findTypeExpr(expr ast.Expr) (dwarf.Type, error) { + dbp.loadPackageMap() + if lit, islit := expr.(*ast.BasicLit); islit && lit.Kind == token.STRING { + // Allow users to specify type names verbatim as quoted + // string. Useful as a catch-all workaround for cases where we don't + // parse/serialize types correctly or can not resolve package paths. + typn, _ := strconv.Unquote(lit.Value) + return dbp.findType(typn) + } + dbp.expandPackagesInType(expr) + if snode, ok := expr.(*ast.StarExpr); ok { + // Pointer types only appear in the dwarf informations when + // a pointer to the type is used in the target program, here + // we create a pointer type on the fly so that the user can + // specify a pointer to any variable used in the target program + ptyp, err := dbp.findTypeExpr(snode.X) + if err != nil { + return nil, err + } + return dbp.pointerTo(ptyp), nil + } + return dbp.findType(exprToString(expr)) +} + +func complexType(typename string) bool { + for _, ch := range typename { + switch ch { + case '*', '[', '<', '{', '(', ' ': + return true + } + } + return false +} + +func (dbp *Process) loadPackageMap() error { + if dbp.packageMap != nil { + return nil + } + dbp.packageMap = map[string]string{} + reader := dbp.DwarfReader() + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return err + } + + if entry.Tag != dwarf.TagTypedef && entry.Tag != dwarf.TagBaseType && entry.Tag != dwarf.TagClassType && entry.Tag != dwarf.TagStructType { + continue + } + + typename, ok := entry.Val(dwarf.AttrName).(string) + if !ok || complexType(typename) { + continue + } + + dot := strings.LastIndex(typename, ".") + if dot < 0 { + continue + } + path := typename[:dot] + slash := strings.LastIndex(path, "/") + if slash < 0 || slash+1 >= len(path) { + continue + } + name := path[slash+1:] + dbp.packageMap[name] = path + } + return nil +} + +type sortFunctionsDebugInfoByLowpc []functionDebugInfo + +func (v sortFunctionsDebugInfoByLowpc) Len() int { return len(v) } +func (v sortFunctionsDebugInfoByLowpc) Less(i, j int) bool { return v[i].lowpc < v[j].lowpc } +func (v sortFunctionsDebugInfoByLowpc) Swap(i, j int) { + temp := v[i] + v[i] = v[j] + v[j] = temp +} + +func (dbp *Process) loadDebugInfoMaps(wg *sync.WaitGroup) { + defer wg.Done() + dbp.types = make(map[string]dwarf.Offset) + dbp.functions = []functionDebugInfo{} + reader := dbp.DwarfReader() + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + break + } + switch entry.Tag { + case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType: + name, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + if _, exists := dbp.types[name]; !exists { + dbp.types[name] = entry.Offset + } + case dwarf.TagSubprogram: + lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64) + if !ok { + continue + } + highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64) + if !ok { + continue + } + dbp.functions = append(dbp.functions, functionDebugInfo{lowpc, highpc, entry.Offset}) + } + } + sort.Sort(sortFunctionsDebugInfoByLowpc(dbp.functions)) +} + +func (dbp *Process) findFunctionDebugInfo(pc uint64) (dwarf.Offset, error) { + i := sort.Search(len(dbp.functions), func(i int) bool { + fn := dbp.functions[i] + return pc <= fn.lowpc || (fn.lowpc <= pc && pc < fn.highpc) + }) + if i != len(dbp.functions) { + fn := dbp.functions[i] + if fn.lowpc <= pc && pc < fn.highpc { + return fn.offset, nil + } + } + return 0, errors.New("unable to find function context") +} + +func (dbp *Process) expandPackagesInType(expr ast.Expr) { + switch e := expr.(type) { + case *ast.ArrayType: + dbp.expandPackagesInType(e.Elt) + case *ast.ChanType: + dbp.expandPackagesInType(e.Value) + case *ast.FuncType: + for i := range e.Params.List { + dbp.expandPackagesInType(e.Params.List[i].Type) + } + if e.Results != nil { + for i := range e.Results.List { + dbp.expandPackagesInType(e.Results.List[i].Type) + } + } + case *ast.MapType: + dbp.expandPackagesInType(e.Key) + dbp.expandPackagesInType(e.Value) + case *ast.ParenExpr: + dbp.expandPackagesInType(e.X) + case *ast.SelectorExpr: + switch x := e.X.(type) { + case *ast.Ident: + if path, ok := dbp.packageMap[x.Name]; ok { + x.Name = path + } + default: + dbp.expandPackagesInType(e.X) + } + case *ast.StarExpr: + dbp.expandPackagesInType(e.X) + default: + // nothing to do + } +} + +type nameOfRuntimeTypeEntry struct { + typename string + kind int64 +} + +// Returns the type name of the type described in _type. +// _type is a non-loaded Variable pointing to runtime._type struct in the target. +// The returned string is in the format that's used in DWARF data +func nameOfRuntimeType(_type *Variable) (typename string, kind int64, err error) { + if e, ok := _type.dbp.nameOfRuntimeType[_type.Addr]; ok { + return e.typename, e.kind, nil + } + + var tflag int64 + + if tflagField := _type.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil { + tflag, _ = constant.Int64Val(tflagField.Value) + } + if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil { + kind, _ = constant.Int64Val(kindField.Value) + } + + // Named types are defined by a 'type' expression, everything else + // (for example pointers to named types) are not considered named. + if tflag&tflagNamed != 0 { + typename, err = nameOfNamedRuntimeType(_type, kind, tflag) + return typename, kind, err + } else { + typename, err = nameOfUnnamedRuntimeType(_type, kind, tflag) + return typename, kind, err + } + + _type.dbp.nameOfRuntimeType[_type.Addr] = nameOfRuntimeTypeEntry{typename, kind} + + return typename, kind, nil +} + +// The layout of a runtime._type struct is as follows: +// +// +// +// with the 'uncommon type struct' being optional +// +// For named types first we extract the type name from the 'str' +// field in the runtime._type struct. +// Then we prepend the package path from the runtime.uncommontype +// struct, when it exists. +// +// To find out the memory address of the runtime.uncommontype struct +// we first cast the Variable pointing to the runtime._type struct +// to a struct specific to the type's kind (for example, if the type +// being described is a slice type the variable will be specialized +// to a runtime.slicetype). +func nameOfNamedRuntimeType(_type *Variable, kind, tflag int64) (typename string, err error) { + var strOff int64 + if strField := _type.loadFieldNamed("str"); strField != nil && strField.Value != nil { + strOff, _ = constant.Int64Val(strField.Value) + } else { + return "", errors.New("could not find str field") + } + + // The following code is adapted from reflect.(*rtype).Name. + // For a description of how memory is organized for type names read + // the comment to 'type name struct' in $GOROOT/src/reflect/type.go + + typename, _, _, err = _type.dbp.resolveNameOff(_type.Addr, uintptr(strOff)) + if err != nil { + return "", err + } + + if tflag&tflagExtraStar != 0 { + typename = typename[1:] + } + + if i := strings.Index(typename, "."); i >= 0 { + typename = typename[i+1:] + } else { + return typename, nil + } + + // The following code is adapted from reflect.(*rtype).PkgPath in + // $GOROOT/src/reflect/type.go + + _type, err = specificRuntimeType(_type, kind) + if err != nil { + return "", err + } + + if ut := uncommon(_type, tflag); ut != nil { + if pkgPathField := ut.loadFieldNamed("pkgpath"); pkgPathField != nil && pkgPathField.Value != nil { + pkgPathOff, _ := constant.Int64Val(pkgPathField.Value) + pkgPath, _, _, err := _type.dbp.resolveNameOff(_type.Addr, uintptr(pkgPathOff)) + if err != nil { + return "", err + } + typename = pkgPath + "." + typename + } + } + + return typename, nil +} + +func nameOfUnnamedRuntimeType(_type *Variable, kind, tflag int64) (string, error) { + _type, err := specificRuntimeType(_type, kind) + if err != nil { + return "", err + } + + // The types referred to here are defined in $GOROOT/src/runtime/type.go + switch reflect.Kind(kind & kindMask) { + case reflect.Array: + var len int64 + if lenField := _type.loadFieldNamed("len"); lenField != nil && lenField.Value != nil { + len, _ = constant.Int64Val(lenField.Value) + } + elemname, err := fieldToType(_type, "elem") + if err != nil { + return "", err + } + return fmt.Sprintf("[%d]%s", len, elemname), nil + case reflect.Chan: + elemname, err := fieldToType(_type, "elem") + if err != nil { + return "", err + } + return "chan " + elemname, nil + case reflect.Func: + return nameOfFuncRuntimeType(_type, tflag, true) + case reflect.Interface: + return nameOfInterfaceRuntimeType(_type, kind, tflag) + case reflect.Map: + keyname, err := fieldToType(_type, "key") + if err != nil { + return "", err + } + elemname, err := fieldToType(_type, "elem") + if err != nil { + return "", err + } + return "map[" + keyname + "]" + elemname, nil + case reflect.Ptr: + elemname, err := fieldToType(_type, "elem") + if err != nil { + return "", err + } + return "*" + elemname, nil + case reflect.Slice: + elemname, err := fieldToType(_type, "elem") + if err != nil { + return "", err + } + return "[]" + elemname, nil + case reflect.Struct: + return nameOfStructRuntimeType(_type, kind, tflag) + default: + return nameOfNamedRuntimeType(_type, kind, tflag) + } +} + +// Returns the expression describing an anonymous function type. +// A runtime.functype is followed by a runtime.uncommontype +// (optional) and then by an array of pointers to runtime._type, +// one for each input and output argument. +func nameOfFuncRuntimeType(_type *Variable, tflag int64, anonymous bool) (string, error) { + rtyp, err := _type.dbp.findType("runtime._type") + if err != nil { + return "", err + } + prtyp := _type.dbp.pointerTo(rtyp) + + uadd := _type.RealType.Common().ByteSize + if ut := uncommon(_type, tflag); ut != nil { + uadd += ut.RealType.Common().ByteSize + } + + var inCount, outCount int64 + if inCountField := _type.loadFieldNamed("inCount"); inCountField != nil && inCountField.Value != nil { + inCount, _ = constant.Int64Val(inCountField.Value) + } + if outCountField := _type.loadFieldNamed("outCount"); outCountField != nil && outCountField.Value != nil { + outCount, _ = constant.Int64Val(outCountField.Value) + // only the lowest 15 bits of outCount are used, rest are flags + outCount = outCount & (1<<15 - 1) + } + + cursortyp := _type.newVariable("", _type.Addr+uintptr(uadd), prtyp) + var buf bytes.Buffer + if anonymous { + buf.WriteString("func(") + } else { + buf.WriteString("(") + } + + for i := int64(0); i < inCount; i++ { + argtype := cursortyp.maybeDereference() + cursortyp.Addr += uintptr(_type.dbp.arch.PtrSize()) + argtypename, _, err := nameOfRuntimeType(argtype) + if err != nil { + return "", err + } + buf.WriteString(argtypename) + if i != inCount-1 { + buf.WriteString(", ") + } + } + buf.WriteString(")") + + switch outCount { + case 0: + // nothing to do + case 1: + buf.WriteString(" ") + argtype := cursortyp.maybeDereference() + argtypename, _, err := nameOfRuntimeType(argtype) + if err != nil { + return "", err + } + buf.WriteString(argtypename) + default: + buf.WriteString(" (") + for i := int64(0); i < outCount; i++ { + argtype := cursortyp.maybeDereference() + cursortyp.Addr += uintptr(_type.dbp.arch.PtrSize()) + argtypename, _, err := nameOfRuntimeType(argtype) + if err != nil { + return "", err + } + buf.WriteString(argtypename) + if i != inCount-1 { + buf.WriteString(", ") + } + } + buf.WriteString(")") + } + return buf.String(), nil +} + +func nameOfInterfaceRuntimeType(_type *Variable, kind, tflag int64) (string, error) { + var buf bytes.Buffer + buf.WriteString("interface {") + + methods, _ := _type.structMember("methods") + methods.loadArrayValues(0, LoadConfig{false, 1, 0, 4096, -1}) + if methods.Unreadable != nil { + return "", nil + } + + if len(methods.Children) == 0 { + buf.WriteString("}") + return buf.String(), nil + } else { + buf.WriteString(" ") + } + + for i, im := range methods.Children { + var methodname, methodtype string + for i := range im.Children { + switch im.Children[i].Name { + case "name": + nameoff, _ := constant.Int64Val(im.Children[i].Value) + var err error + methodname, _, _, err = _type.dbp.resolveNameOff(_type.Addr, uintptr(nameoff)) + if err != nil { + return "", err + } + + case "typ": + typeoff, _ := constant.Int64Val(im.Children[i].Value) + typ, err := _type.dbp.resolveTypeOff(_type.Addr, uintptr(typeoff)) + if err != nil { + return "", err + } + typ, err = specificRuntimeType(typ, int64(reflect.Func)) + if err != nil { + return "", err + } + var tflag int64 + if tflagField := typ.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil { + tflag, _ = constant.Int64Val(tflagField.Value) + } + methodtype, err = nameOfFuncRuntimeType(typ, tflag, false) + if err != nil { + return "", err + } + } + } + + buf.WriteString(methodname) + buf.WriteString(methodtype) + + if i != len(methods.Children)-1 { + buf.WriteString("; ") + } else { + buf.WriteString(" }") + } + } + return buf.String(), nil +} + +func nameOfStructRuntimeType(_type *Variable, kind, tflag int64) (string, error) { + var buf bytes.Buffer + buf.WriteString("struct {") + + fields, _ := _type.structMember("fields") + fields.loadArrayValues(0, LoadConfig{false, 1, 0, 4096, -1}) + if fields.Unreadable != nil { + return "", fields.Unreadable + } + + if len(fields.Children) == 0 { + buf.WriteString("}") + return buf.String(), nil + } else { + buf.WriteString(" ") + } + + for i, field := range fields.Children { + var fieldname, fieldtypename string + var typeField *Variable + for i := range field.Children { + switch field.Children[i].Name { + case "name": + nameoff, _ := constant.Int64Val(field.Children[i].Value) + var err error + fieldname, _, _, err = _type.dbp.loadName(uintptr(nameoff)) + if err != nil { + return "", err + } + + case "typ": + typeField = field.Children[i].maybeDereference() + var err error + fieldtypename, _, err = nameOfRuntimeType(typeField) + if err != nil { + return "", err + } + } + } + + // fieldname will be the empty string for anonymous fields + if fieldname != "" { + buf.WriteString(fieldname) + buf.WriteString(" ") + } + buf.WriteString(fieldtypename) + if i != len(fields.Children)-1 { + buf.WriteString("; ") + } else { + buf.WriteString(" }") + } + } + + return buf.String(), nil +} + +func fieldToType(_type *Variable, fieldName string) (string, error) { + typeField, err := _type.structMember(fieldName) + if err != nil { + return "", err + } + typeField = typeField.maybeDereference() + typename, _, err := nameOfRuntimeType(typeField) + return typename, err +} + +func specificRuntimeType(_type *Variable, kind int64) (*Variable, error) { + rtyp, err := _type.dbp.findType("runtime._type") + if err != nil { + return nil, err + } + prtyp := _type.dbp.pointerTo(rtyp) + + uintptrtyp, err := _type.dbp.findType("uintptr") + if err != nil { + return nil, err + } + + uint32typ := &dwarf.UintType{dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 4, Name: "uint32"}}} + uint16typ := &dwarf.UintType{dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 2, Name: "uint16"}}} + + newStructType := func(name string, sz uintptr) *dwarf.StructType { + return &dwarf.StructType{dwarf.CommonType{Name: name, ByteSize: int64(sz)}, name, "struct", nil, false} + } + + appendField := func(typ *dwarf.StructType, name string, fieldtype dwarf.Type, off uintptr) { + typ.Field = append(typ.Field, &dwarf.StructField{Name: name, ByteOffset: int64(off), Type: fieldtype}) + } + + newSliceType := func(elemtype dwarf.Type) *dwarf.SliceType { + r := newStructType("[]"+elemtype.Common().Name, uintptr(3*uintptrtyp.Size())) + appendField(r, "array", _type.dbp.pointerTo(elemtype), 0) + appendField(r, "len", uintptrtyp, uintptr(uintptrtyp.Size())) + appendField(r, "cap", uintptrtyp, uintptr(2*uintptrtyp.Size())) + return &dwarf.SliceType{StructType: *r, ElemType: elemtype} + } + + var typ *dwarf.StructType + + type rtype struct { + size uintptr + ptrdata uintptr + hash uint32 // hash of type; avoids computation in hash tables + tflag uint8 // extra type information flags + align uint8 // alignment of variable with this type + fieldAlign uint8 // alignment of struct field with this type + kind uint8 // enumeration for C + alg *byte // algorithm table + gcdata *byte // garbage collection data + str int32 // string form + ptrToThis int32 // type for pointer to this type, may be zero + } + + switch reflect.Kind(kind & kindMask) { + case reflect.Array: + // runtime.arraytype + var a struct { + rtype + elem *rtype // array element type + slice *rtype // slice type + len uintptr + } + typ = newStructType("runtime.arraytype", unsafe.Sizeof(a)) + appendField(typ, "elem", prtyp, unsafe.Offsetof(a.elem)) + appendField(typ, "len", uintptrtyp, unsafe.Offsetof(a.len)) + case reflect.Chan: + // runtime.chantype + var a struct { + rtype + elem *rtype // channel element type + dir uintptr // channel direction (ChanDir) + } + typ = newStructType("runtime.chantype", unsafe.Sizeof(a)) + appendField(typ, "elem", prtyp, unsafe.Offsetof(a.elem)) + case reflect.Func: + // runtime.functype + var a struct { + rtype `reflect:"func"` + inCount uint16 + outCount uint16 // top bit is set if last input parameter is ... + } + typ = newStructType("runtime.functype", unsafe.Sizeof(a)) + appendField(typ, "inCount", uint16typ, unsafe.Offsetof(a.inCount)) + appendField(typ, "outCount", uint16typ, unsafe.Offsetof(a.outCount)) + case reflect.Interface: + // runtime.imethod + type imethod struct { + name uint32 // name of method + typ uint32 // .(*FuncType) underneath + } + + var im imethod + + // runtime.interfacetype + var a struct { + rtype `reflect:"interface"` + pkgPath *byte // import path + methods []imethod // sorted by hash + } + + imethodtype := newStructType("runtime.imethod", unsafe.Sizeof(im)) + appendField(imethodtype, "name", uint32typ, unsafe.Offsetof(im.name)) + appendField(imethodtype, "typ", uint32typ, unsafe.Offsetof(im.typ)) + typ = newStructType("runtime.interfacetype", unsafe.Sizeof(a)) + appendField(typ, "methods", newSliceType(imethodtype), unsafe.Offsetof(a.methods)) + case reflect.Map: + // runtime.maptype + var a struct { + rtype `reflect:"map"` + key *rtype // map key type + elem *rtype // map element (value) type + bucket *rtype // internal bucket structure + hmap *rtype // internal map header + keysize uint8 // size of key slot + indirectkey uint8 // store ptr to key instead of key itself + valuesize uint8 // size of value slot + indirectvalue uint8 // store ptr to value instead of value itself + bucketsize uint16 // size of bucket + reflexivekey bool // true if k==k for all keys + needkeyupdate bool // true if we need to update key on an overwrite + } + typ = newStructType("runtime.maptype", unsafe.Sizeof(a)) + appendField(typ, "key", prtyp, unsafe.Offsetof(a.key)) + appendField(typ, "elem", prtyp, unsafe.Offsetof(a.elem)) + case reflect.Ptr: + // runtime.ptrtype + var a struct { + rtype `reflect:"ptr"` + elem *rtype // pointer element (pointed at) type + } + typ = newStructType("runtime.ptrtype", unsafe.Sizeof(a)) + appendField(typ, "elem", prtyp, unsafe.Offsetof(a.elem)) + case reflect.Slice: + // runtime.slicetype + var a struct { + rtype `reflect:"slice"` + elem *rtype // slice element type + } + + typ = newStructType("runtime.slicetype", unsafe.Sizeof(a)) + appendField(typ, "elem", prtyp, unsafe.Offsetof(a.elem)) + case reflect.Struct: + // runtime.structtype + type structField struct { + name *byte // name is empty for embedded fields + typ *rtype // type of field + offset uintptr // byte offset of field within struct + } + + var sf structField + + var a struct { + rtype `reflect:"struct"` + pkgPath *byte + fields []structField // sorted by offset + } + + fieldtype := newStructType("runtime.structtype", unsafe.Sizeof(sf)) + appendField(fieldtype, "name", uintptrtyp, unsafe.Offsetof(sf.name)) + appendField(fieldtype, "typ", prtyp, unsafe.Offsetof(sf.typ)) + typ = newStructType("runtime.structtype", unsafe.Sizeof(a)) + appendField(typ, "fields", newSliceType(fieldtype), unsafe.Offsetof(a.fields)) + default: + return _type, nil + } + + return _type.newVariable(_type.Name, _type.Addr, typ), nil +} + +// See reflect.(*rtype).uncommon in $GOROOT/src/reflect/type.go +func uncommon(_type *Variable, tflag int64) *Variable { + if tflag&tflagUncommon == 0 { + return nil + } + + typ, err := _type.dbp.findType("runtime.uncommontype") + if err != nil { + return nil + } + + return _type.newVariable(_type.Name, _type.Addr+uintptr(_type.RealType.Size()), typ) +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/variables.go b/vendor/github.com/derekparker/delve/pkg/proc/variables.go new file mode 100644 index 0000000..f243d04 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/variables.go @@ -0,0 +1,1723 @@ +package proc + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "go/constant" + "go/parser" + "go/token" + "math" + "reflect" + "strings" + "unsafe" + + "github.com/derekparker/delve/pkg/dwarf/op" + "github.com/derekparker/delve/pkg/dwarf/reader" + "golang.org/x/debug/dwarf" +) + +const ( + maxErrCount = 3 // Max number of read errors to accept while evaluating slices, arrays and structs + + maxArrayStridePrefetch = 1024 // Maximum size of array stride for which we will prefetch the array contents + + chanRecv = "chan receive" + chanSend = "chan send" + + hashTophashEmpty = 0 // used by map reading code, indicates an empty bucket + hashMinTopHash = 4 // used by map reading code, indicates minimum value of tophash that isn't empty or evacuated +) + +type FloatSpecial uint8 + +const ( + FloatIsNormal FloatSpecial = iota + FloatIsNaN + FloatIsPosInf + FloatIsNegInf +) + +// Variable represents a variable. It contains the address, name, +// type and other information parsed from both the Dwarf information +// and the memory of the debugged process. +// If OnlyAddr is true, the variables value has not been loaded. +type Variable struct { + Addr uintptr + OnlyAddr bool + Name string + DwarfType dwarf.Type + RealType dwarf.Type + Kind reflect.Kind + mem memoryReadWriter + dbp *Process + + Value constant.Value + FloatSpecial FloatSpecial + + Len int64 + Cap int64 + + // Base address of arrays, Base address of the backing array for slices (0 for nil slices) + // Base address of the backing byte array for strings + // address of the struct backing chan and map variables + // address of the function entry point for function variables (0 for nil function pointers) + Base uintptr + stride int64 + fieldType dwarf.Type + + // number of elements to skip when loading a map + mapSkip int + + Children []Variable + + loaded bool + Unreadable error +} + +type LoadConfig struct { + // FollowPointers requests pointers to be automatically dereferenced. + FollowPointers bool + // MaxVariableRecurse is how far to recurse when evaluating nested types. + MaxVariableRecurse int + // MaxStringLen is the maximum number of bytes read from a string + MaxStringLen int + // MaxArrayValues is the maximum number of elements read from an array, a slice or a map. + MaxArrayValues int + // MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields. + MaxStructFields int +} + +var loadSingleValue = LoadConfig{false, 0, 64, 0, 0} +var loadFullValue = LoadConfig{true, 1, 64, 64, -1} + +// M represents a runtime M (OS thread) structure. +type M struct { + procid int // Thread ID or port. + spinning uint8 // Busy looping. + blocked uint8 // Waiting on futex / semaphore. + curg uintptr // Current G running on this thread. +} + +// G status, from: src/runtime/runtime2.go +const ( + Gidle uint64 = iota // 0 + Grunnable // 1 runnable and on a run queue + Grunning // 2 + Gsyscall // 3 + Gwaiting // 4 + GmoribundUnused // 5 currently unused, but hardcoded in gdb scripts + Gdead // 6 + Genqueue // 7 Only the Gscanenqueue is used. + Gcopystack // 8 in this state when newstack is moving the stack +) + +// G represents a runtime G (goroutine) structure (at least the +// fields that Delve is interested in). +type G struct { + ID int // Goroutine ID + PC uint64 // PC of goroutine when it was parked. + SP uint64 // SP of goroutine when it was parked. + GoPC uint64 // PC of 'go' statement that created this goroutine. + WaitReason string // Reason for goroutine being parked. + Status uint64 + stkbarVar *Variable // stkbar field of g struct + stkbarPos int // stkbarPos field of g struct + + // Information on goroutine location + CurrentLoc Location + + // Thread that this goroutine is currently allocated to + thread *Thread + + variable *Variable + dbp *Process +} + +// EvalScope is the scope for variable evaluation. Contains the thread, +// current location (PC), and canonical frame address. +type EvalScope struct { + Thread *Thread + PC uint64 + CFA int64 +} + +// IsNilErr is returned when a variable is nil. +type IsNilErr struct { + name string +} + +func (err *IsNilErr) Error() string { + return fmt.Sprintf("%s is nil", err.name) +} + +func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable { + return newVariable(name, addr, dwarfType, scope.Thread.dbp, scope.Thread) +} + +func (t *Thread) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable { + return newVariable(name, addr, dwarfType, t.dbp, t) +} + +func (v *Variable) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable { + return newVariable(name, addr, dwarfType, v.dbp, v.mem) +} + +func newVariable(name string, addr uintptr, dwarfType dwarf.Type, dbp *Process, mem memoryReadWriter) *Variable { + v := &Variable{ + Name: name, + Addr: addr, + DwarfType: dwarfType, + mem: mem, + dbp: dbp, + } + + v.RealType = resolveTypedef(v.DwarfType) + + switch t := v.RealType.(type) { + case *dwarf.PtrType: + v.Kind = reflect.Ptr + if _, isvoid := t.Type.(*dwarf.VoidType); isvoid { + v.Kind = reflect.UnsafePointer + } + case *dwarf.ChanType: + v.Kind = reflect.Chan + case *dwarf.MapType: + v.Kind = reflect.Map + case *dwarf.StringType: + v.Kind = reflect.String + v.stride = 1 + v.fieldType = &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 1, Name: "byte"}, BitSize: 8, BitOffset: 0}} + if v.Addr != 0 { + v.Base, v.Len, v.Unreadable = readStringInfo(v.mem, v.dbp.arch, v.Addr) + } + case *dwarf.SliceType: + v.Kind = reflect.Slice + if v.Addr != 0 { + v.loadSliceInfo(t) + } + case *dwarf.InterfaceType: + v.Kind = reflect.Interface + case *dwarf.StructType: + v.Kind = reflect.Struct + case *dwarf.ArrayType: + v.Kind = reflect.Array + v.Base = v.Addr + v.Len = t.Count + v.Cap = -1 + v.fieldType = t.Type + v.stride = 0 + + if t.Count > 0 { + v.stride = t.ByteSize / t.Count + } + case *dwarf.ComplexType: + switch t.ByteSize { + case 8: + v.Kind = reflect.Complex64 + case 16: + v.Kind = reflect.Complex128 + } + case *dwarf.IntType: + v.Kind = reflect.Int + case *dwarf.UintType: + v.Kind = reflect.Uint + case *dwarf.FloatType: + switch t.ByteSize { + case 4: + v.Kind = reflect.Float32 + case 8: + v.Kind = reflect.Float64 + } + case *dwarf.BoolType: + v.Kind = reflect.Bool + case *dwarf.FuncType: + v.Kind = reflect.Func + case *dwarf.VoidType: + v.Kind = reflect.Invalid + case *dwarf.UnspecifiedType: + v.Kind = reflect.Invalid + default: + v.Unreadable = fmt.Errorf("Unknown type: %T", t) + } + + return v +} + +func resolveTypedef(typ dwarf.Type) dwarf.Type { + for { + if tt, ok := typ.(*dwarf.TypedefType); ok { + typ = tt.Type + } else { + return typ + } + } +} + +func newConstant(val constant.Value, mem memoryReadWriter) *Variable { + v := &Variable{Value: val, mem: mem, loaded: true} + switch val.Kind() { + case constant.Int: + v.Kind = reflect.Int + case constant.Float: + v.Kind = reflect.Float64 + case constant.Bool: + v.Kind = reflect.Bool + case constant.Complex: + v.Kind = reflect.Complex128 + case constant.String: + v.Kind = reflect.String + v.Len = int64(len(constant.StringVal(val))) + } + return v +} + +var nilVariable = &Variable{ + Name: "nil", + Addr: 0, + Base: 0, + Kind: reflect.Ptr, + Children: []Variable{{Addr: 0, OnlyAddr: true}}, +} + +func (v *Variable) clone() *Variable { + r := *v + return &r +} + +// TypeString returns the string representation +// of the type of this variable. +func (v *Variable) TypeString() string { + if v == nilVariable { + return "nil" + } + if v.DwarfType != nil { + return v.DwarfType.Common().Name + } + return v.Kind.String() +} + +func (v *Variable) toField(field *dwarf.StructField) (*Variable, error) { + if v.Unreadable != nil { + return v.clone(), nil + } + if v.Addr == 0 { + return nil, &IsNilErr{v.Name} + } + + name := "" + if v.Name != "" { + parts := strings.Split(field.Name, ".") + if len(parts) > 1 { + name = fmt.Sprintf("%s.%s", v.Name, parts[1]) + } else { + name = fmt.Sprintf("%s.%s", v.Name, field.Name) + } + } + return v.newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type), nil +} + +// DwarfReader returns the DwarfReader containing the +// Dwarf information for the target process. +func (scope *EvalScope) DwarfReader() *reader.Reader { + return scope.Thread.dbp.DwarfReader() +} + +// Type returns the Dwarf type entry at `offset`. +func (scope *EvalScope) Type(offset dwarf.Offset) (dwarf.Type, error) { + return scope.Thread.dbp.dwarf.Type(offset) +} + +// PtrSize returns the size of a pointer. +func (scope *EvalScope) PtrSize() int { + return scope.Thread.dbp.arch.PtrSize() +} + +// ChanRecvBlocked returns whether the goroutine is blocked on +// a channel read operation. +func (g *G) ChanRecvBlocked() bool { + return (g.thread == nil) && (g.WaitReason == chanRecv) +} + +// chanRecvReturnAddr returns the address of the return from a channel read. +func (g *G) chanRecvReturnAddr(dbp *Process) (uint64, error) { + locs, err := g.Stacktrace(4) + if err != nil { + return 0, err + } + topLoc := locs[len(locs)-1] + return topLoc.Current.PC, nil +} + +// NoGError returned when a G could not be found +// for a specific thread. +type NoGError struct { + tid int +} + +func (ng NoGError) Error() string { + return fmt.Sprintf("no G executing on thread %d", ng.tid) +} + +func (gvar *Variable) parseG() (*G, error) { + mem := gvar.mem + dbp := gvar.dbp + gaddr := uint64(gvar.Addr) + _, deref := gvar.RealType.(*dwarf.PtrType) + + if deref { + gaddrbytes, err := mem.readMemory(uintptr(gaddr), dbp.arch.PtrSize()) + if err != nil { + return nil, fmt.Errorf("error derefing *G %s", err) + } + gaddr = binary.LittleEndian.Uint64(gaddrbytes) + } + if gaddr == 0 { + id := 0 + if thread, ok := mem.(*Thread); ok { + id = thread.ID + } + return nil, NoGError{tid: id} + } + for { + if _, isptr := gvar.RealType.(*dwarf.PtrType); !isptr { + break + } + gvar = gvar.maybeDereference() + } + gvar.loadValue(LoadConfig{false, 1, 64, 0, -1}) + if gvar.Unreadable != nil { + return nil, gvar.Unreadable + } + schedVar := gvar.fieldVariable("sched") + pc, _ := constant.Int64Val(schedVar.fieldVariable("pc").Value) + sp, _ := constant.Int64Val(schedVar.fieldVariable("sp").Value) + id, _ := constant.Int64Val(gvar.fieldVariable("goid").Value) + gopc, _ := constant.Int64Val(gvar.fieldVariable("gopc").Value) + waitReason := constant.StringVal(gvar.fieldVariable("waitreason").Value) + + stkbarVar, _ := gvar.structMember("stkbar") + stkbarVarPosFld := gvar.fieldVariable("stkbarPos") + var stkbarPos int64 + if stkbarVarPosFld != nil { // stack barriers were removed in Go 1.9 + stkbarPos, _ = constant.Int64Val(stkbarVarPosFld.Value) + } + + status, _ := constant.Int64Val(gvar.fieldVariable("atomicstatus").Value) + f, l, fn := gvar.dbp.goSymTable.PCToLine(uint64(pc)) + g := &G{ + ID: int(id), + GoPC: uint64(gopc), + PC: uint64(pc), + SP: uint64(sp), + WaitReason: waitReason, + Status: uint64(status), + CurrentLoc: Location{PC: uint64(pc), File: f, Line: l, Fn: fn}, + variable: gvar, + stkbarVar: stkbarVar, + stkbarPos: int(stkbarPos), + dbp: gvar.dbp, + } + return g, nil +} + +func (v *Variable) loadFieldNamed(name string) *Variable { + v, err := v.structMember(name) + if err != nil { + return nil + } + v.loadValue(loadFullValue) + if v.Unreadable != nil { + return nil + } + return v +} + +func (v *Variable) fieldVariable(name string) *Variable { + for i := range v.Children { + if child := &v.Children[i]; child.Name == name { + return child + } + } + return nil +} + +// PC of entry to top-most deferred function. +func (g *G) DeferPC() uint64 { + if g.variable.Unreadable != nil { + return 0 + } + d := g.variable.fieldVariable("_defer").maybeDereference() + if d.Addr == 0 { + return 0 + } + d.loadValue(LoadConfig{false, 1, 64, 0, -1}) + if d.Unreadable != nil { + return 0 + } + fnvar := d.fieldVariable("fn").maybeDereference() + if fnvar.Addr == 0 { + return 0 + } + fnvar.loadValue(LoadConfig{false, 1, 64, 0, -1}) + if fnvar.Unreadable != nil { + return 0 + } + deferPC, _ := constant.Int64Val(fnvar.fieldVariable("fn").Value) + return uint64(deferPC) +} + +// From $GOROOT/src/runtime/traceback.go:597 +// isExportedRuntime reports whether name is an exported runtime function. +// It is only for runtime functions, so ASCII A-Z is fine. +func isExportedRuntime(name string) bool { + const n = len("runtime.") + return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' +} + +// UserCurrent returns the location the users code is at, +// or was at before entering a runtime function. +func (g *G) UserCurrent() Location { + it, err := g.stackIterator() + if err != nil { + return g.CurrentLoc + } + for it.Next() { + frame := it.Frame() + if frame.Call.Fn != nil { + name := frame.Call.Fn.Name + if (strings.Index(name, ".") >= 0) && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) { + return frame.Call + } + } + } + return g.CurrentLoc +} + +// Go returns the location of the 'go' statement +// that spawned this goroutine. +func (g *G) Go() Location { + f, l, fn := g.dbp.goSymTable.PCToLine(g.GoPC) + return Location{PC: g.GoPC, File: f, Line: l, Fn: fn} +} + +// Returns the list of saved return addresses used by stack barriers +func (g *G) stkbar() ([]savedLR, error) { + if g.stkbarVar == nil { // stack barriers were removed in Go 1.9 + return nil, nil + } + g.stkbarVar.loadValue(LoadConfig{false, 1, 0, int(g.stkbarVar.Len), 3}) + if g.stkbarVar.Unreadable != nil { + return nil, fmt.Errorf("unreadable stkbar: %v\n", g.stkbarVar.Unreadable) + } + r := make([]savedLR, len(g.stkbarVar.Children)) + for i, child := range g.stkbarVar.Children { + for _, field := range child.Children { + switch field.Name { + case "savedLRPtr": + ptr, _ := constant.Int64Val(field.Value) + r[i].ptr = uint64(ptr) + case "savedLRVal": + val, _ := constant.Int64Val(field.Value) + r[i].val = uint64(val) + } + } + } + return r, nil +} + +// EvalVariable returns the value of the given expression (backwards compatibility). +func (scope *EvalScope) EvalVariable(name string, cfg LoadConfig) (*Variable, error) { + return scope.EvalExpression(name, cfg) +} + +// SetVariable sets the value of the named variable +func (scope *EvalScope) SetVariable(name, value string) error { + t, err := parser.ParseExpr(name) + if err != nil { + return err + } + + xv, err := scope.evalAST(t) + if err != nil { + return err + } + + if xv.Addr == 0 { + return fmt.Errorf("Can not assign to \"%s\"", name) + } + + if xv.Unreadable != nil { + return fmt.Errorf("Expression \"%s\" is unreadable: %v", name, xv.Unreadable) + } + + t, err = parser.ParseExpr(value) + if err != nil { + return err + } + + yv, err := scope.evalAST(t) + if err != nil { + return err + } + + yv.loadValue(loadSingleValue) + + if err := yv.isType(xv.RealType, xv.Kind); err != nil { + return err + } + + if yv.Unreadable != nil { + return fmt.Errorf("Expression \"%s\" is unreadable: %v", value, yv.Unreadable) + } + + return xv.setValue(yv) +} + +func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry, cfg LoadConfig) (*Variable, error) { + rdr := scope.DwarfReader() + v, err := scope.extractVarInfoFromEntry(entry, rdr) + if err != nil { + return nil, err + } + return v, nil +} + +func (scope *EvalScope) extractVarInfo(varName string) (*Variable, error) { + reader := scope.DwarfReader() + off, err := scope.Thread.dbp.findFunctionDebugInfo(scope.PC) + if err != nil { + return nil, err + } + reader.Seek(off) + reader.Next() + + for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() { + if err != nil { + return nil, err + } + if entry.Tag == 0 { + break + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + + if n == varName { + return scope.extractVarInfoFromEntry(entry, reader) + } + } + return nil, fmt.Errorf("could not find symbol value for %s", varName) +} + +// LocalVariables returns all local variables from the current function scope. +func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) { + return scope.variablesByTag(dwarf.TagVariable, cfg) +} + +// FunctionArguments returns the name, value, and type of all current function arguments. +func (scope *EvalScope) FunctionArguments(cfg LoadConfig) ([]*Variable, error) { + return scope.variablesByTag(dwarf.TagFormalParameter, cfg) +} + +// PackageVariables returns the name, value, and type of all package variables in the application. +func (scope *EvalScope) PackageVariables(cfg LoadConfig) ([]*Variable, error) { + var vars []*Variable + reader := scope.DwarfReader() + + var utypoff dwarf.Offset + utypentry, err := reader.SeekToTypeNamed("") + if err == nil { + utypoff = utypentry.Offset + } + + for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() { + if err != nil { + return nil, err + } + + if typoff, ok := entry.Val(dwarf.AttrType).(dwarf.Offset); !ok || typoff == utypoff { + continue + } + + // Ignore errors trying to extract values + val, err := scope.extractVariableFromEntry(entry, cfg) + if err != nil { + continue + } + val.loadValue(cfg) + vars = append(vars, val) + } + + return vars, nil +} + +// EvalPackageVariable will evaluate the package level variable +// specified by 'name'. +func (dbp *Process) EvalPackageVariable(name string, cfg LoadConfig) (*Variable, error) { + scope := &EvalScope{Thread: dbp.currentThread, PC: 0, CFA: 0} + + v, err := scope.packageVarAddr(name) + if err != nil { + return nil, err + } + v.loadValue(cfg) + return v, nil +} + +func (scope *EvalScope) packageVarAddr(name string) (*Variable, error) { + reader := scope.DwarfReader() + for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() { + if err != nil { + return nil, err + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + + if n == name { + return scope.extractVarInfoFromEntry(entry, reader) + } + } + return nil, fmt.Errorf("could not find symbol value for %s", name) +} + +func (v *Variable) structMember(memberName string) (*Variable, error) { + if v.Unreadable != nil { + return v.clone(), nil + } + structVar := v.maybeDereference() + structVar.Name = v.Name + if structVar.Unreadable != nil { + return structVar, nil + } + + switch t := structVar.RealType.(type) { + case *dwarf.StructType: + for _, field := range t.Field { + if field.Name != memberName { + continue + } + return structVar.toField(field) + } + // Check for embedded field only if field was + // not a regular struct member + for _, field := range t.Field { + isEmbeddedStructMember := + (field.Type.Common().Name == field.Name) || + (len(field.Name) > 1 && + field.Name[0] == '*' && + field.Type.Common().Name[1:] == field.Name[1:]) + if !isEmbeddedStructMember { + continue + } + // Check for embedded field referenced by type name + parts := strings.Split(field.Name, ".") + if len(parts) > 1 && parts[1] == memberName { + embeddedVar, err := structVar.toField(field) + if err != nil { + return nil, err + } + return embeddedVar, nil + } + // Recursively check for promoted fields on the embedded field + embeddedVar, err := structVar.toField(field) + if err != nil { + return nil, err + } + embeddedVar.Name = structVar.Name + embeddedField, err := embeddedVar.structMember(memberName) + if embeddedField != nil { + return embeddedField, nil + } + } + return nil, fmt.Errorf("%s has no member %s", v.Name, memberName) + default: + if v.Name == "" { + return nil, fmt.Errorf("type %s is not a struct", structVar.TypeString()) + } + return nil, fmt.Errorf("%s (type %s) is not a struct", v.Name, structVar.TypeString()) + } +} + +// Extracts the name and type of a variable from a dwarf entry +// then executes the instructions given in the DW_AT_location attribute to grab the variable's address +func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry, rdr *reader.Reader) (*Variable, error) { + if entry == nil { + return nil, fmt.Errorf("invalid entry") + } + + if entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagVariable { + return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", entry.Tag.String()) + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + return nil, fmt.Errorf("type assertion failed") + } + + offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset) + if !ok { + return nil, fmt.Errorf("type assertion failed") + } + + t, err := scope.Type(offset) + if err != nil { + return nil, err + } + + instructions, ok := entry.Val(dwarf.AttrLocation).([]byte) + if !ok { + return nil, fmt.Errorf("type assertion failed") + } + + addr, err := op.ExecuteStackProgram(scope.CFA, instructions) + if err != nil { + return nil, err + } + + return scope.newVariable(n, uintptr(addr), t), nil +} + +// If v is a pointer a new variable is returned containing the value pointed by v. +func (v *Variable) maybeDereference() *Variable { + if v.Unreadable != nil { + return v + } + + switch t := v.RealType.(type) { + case *dwarf.PtrType: + ptrval, err := readUintRaw(v.mem, uintptr(v.Addr), t.ByteSize) + r := v.newVariable("", uintptr(ptrval), t.Type) + if err != nil { + r.Unreadable = err + } + + return r + default: + return v + } +} + +// Extracts the value of the variable at the given address. +func (v *Variable) loadValue(cfg LoadConfig) { + v.loadValueInternal(0, cfg) +} + +func (v *Variable) loadValueInternal(recurseLevel int, cfg LoadConfig) { + if v.Unreadable != nil || v.loaded || (v.Addr == 0 && v.Base == 0) { + return + } + + v.loaded = true + switch v.Kind { + case reflect.Ptr, reflect.UnsafePointer: + v.Len = 1 + v.Children = []Variable{*v.maybeDereference()} + if cfg.FollowPointers { + // Don't increase the recursion level when dereferencing pointers + // unless this is a pointer to interface (which could cause an infinite loop) + nextLvl := recurseLevel + if v.Children[0].Kind == reflect.Interface { + nextLvl++ + } + v.Children[0].loadValueInternal(nextLvl, cfg) + } else { + v.Children[0].OnlyAddr = true + } + + case reflect.Chan: + sv := v.clone() + sv.RealType = resolveTypedef(&(sv.RealType.(*dwarf.ChanType).TypedefType)) + sv = sv.maybeDereference() + sv.loadValueInternal(0, loadFullValue) + v.Children = sv.Children + v.Len = sv.Len + v.Base = sv.Addr + + case reflect.Map: + if recurseLevel <= cfg.MaxVariableRecurse { + v.loadMap(recurseLevel, cfg) + } + + case reflect.String: + var val string + val, v.Unreadable = readStringValue(v.mem, v.Base, v.Len, cfg) + v.Value = constant.MakeString(val) + + case reflect.Slice, reflect.Array: + v.loadArrayValues(recurseLevel, cfg) + + case reflect.Struct: + v.mem = cacheMemory(v.mem, v.Addr, int(v.RealType.Size())) + t := v.RealType.(*dwarf.StructType) + v.Len = int64(len(t.Field)) + // Recursively call extractValue to grab + // the value of all the members of the struct. + if recurseLevel <= cfg.MaxVariableRecurse { + v.Children = make([]Variable, 0, len(t.Field)) + for i, field := range t.Field { + if cfg.MaxStructFields >= 0 && len(v.Children) >= cfg.MaxStructFields { + break + } + f, _ := v.toField(field) + v.Children = append(v.Children, *f) + v.Children[i].Name = field.Name + v.Children[i].loadValueInternal(recurseLevel+1, cfg) + } + } + + case reflect.Interface: + v.loadInterface(recurseLevel, true, cfg) + + case reflect.Complex64, reflect.Complex128: + v.readComplex(v.RealType.(*dwarf.ComplexType).ByteSize) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + var val int64 + val, v.Unreadable = readIntRaw(v.mem, v.Addr, v.RealType.(*dwarf.IntType).ByteSize) + v.Value = constant.MakeInt64(val) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + var val uint64 + val, v.Unreadable = readUintRaw(v.mem, v.Addr, v.RealType.(*dwarf.UintType).ByteSize) + v.Value = constant.MakeUint64(val) + + case reflect.Bool: + val, err := v.mem.readMemory(v.Addr, 1) + v.Unreadable = err + if err == nil { + v.Value = constant.MakeBool(val[0] != 0) + } + case reflect.Float32, reflect.Float64: + var val float64 + val, v.Unreadable = v.readFloatRaw(v.RealType.(*dwarf.FloatType).ByteSize) + v.Value = constant.MakeFloat64(val) + switch { + case math.IsInf(val, +1): + v.FloatSpecial = FloatIsPosInf + case math.IsInf(val, -1): + v.FloatSpecial = FloatIsNegInf + case math.IsNaN(val): + v.FloatSpecial = FloatIsNaN + } + case reflect.Func: + v.readFunctionPtr() + default: + v.Unreadable = fmt.Errorf("unknown or unsupported kind: \"%s\"", v.Kind.String()) + } +} + +func (v *Variable) setValue(y *Variable) error { + var err error + switch v.Kind { + case reflect.Float32, reflect.Float64: + f, _ := constant.Float64Val(y.Value) + err = v.writeFloatRaw(f, v.RealType.Size()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, _ := constant.Int64Val(y.Value) + err = v.writeUint(uint64(n), v.RealType.Size()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n, _ := constant.Uint64Val(y.Value) + err = v.writeUint(n, v.RealType.Size()) + case reflect.Bool: + err = v.writeBool(constant.BoolVal(y.Value)) + case reflect.Complex64, reflect.Complex128: + real, _ := constant.Float64Val(constant.Real(y.Value)) + imag, _ := constant.Float64Val(constant.Imag(y.Value)) + err = v.writeComplex(real, imag, v.RealType.Size()) + default: + if t, isptr := v.RealType.(*dwarf.PtrType); isptr { + err = v.writeUint(uint64(y.Children[0].Addr), int64(t.ByteSize)) + } else { + return fmt.Errorf("can not set variables of type %s (not implemented)", v.Kind.String()) + } + } + + return err +} + +func readStringInfo(mem memoryReadWriter, arch Arch, addr uintptr) (uintptr, int64, error) { + // string data structure is always two ptrs in size. Addr, followed by len + // http://research.swtch.com/godata + + mem = cacheMemory(mem, addr, arch.PtrSize()*2) + + // read len + val, err := mem.readMemory(addr+uintptr(arch.PtrSize()), arch.PtrSize()) + if err != nil { + return 0, 0, fmt.Errorf("could not read string len %s", err) + } + strlen := int64(binary.LittleEndian.Uint64(val)) + if strlen < 0 { + return 0, 0, fmt.Errorf("invalid length: %d", strlen) + } + + // read addr + val, err = mem.readMemory(addr, arch.PtrSize()) + if err != nil { + return 0, 0, fmt.Errorf("could not read string pointer %s", err) + } + addr = uintptr(binary.LittleEndian.Uint64(val)) + if addr == 0 { + return 0, 0, nil + } + + return addr, strlen, nil +} + +func readStringValue(mem memoryReadWriter, addr uintptr, strlen int64, cfg LoadConfig) (string, error) { + count := strlen + if count > int64(cfg.MaxStringLen) { + count = int64(cfg.MaxStringLen) + } + + val, err := mem.readMemory(addr, int(count)) + if err != nil { + return "", fmt.Errorf("could not read string at %#v due to %s", addr, err) + } + + retstr := *(*string)(unsafe.Pointer(&val)) + + return retstr, nil +} + +func (v *Variable) loadSliceInfo(t *dwarf.SliceType) { + v.mem = cacheMemory(v.mem, v.Addr, int(t.Size())) + + var err error + for _, f := range t.Field { + switch f.Name { + case "array": + var base uint64 + base, err = readUintRaw(v.mem, uintptr(int64(v.Addr)+f.ByteOffset), f.Type.Size()) + if err == nil { + v.Base = uintptr(base) + // Dereference array type to get value type + ptrType, ok := f.Type.(*dwarf.PtrType) + if !ok { + v.Unreadable = fmt.Errorf("Invalid type %s in slice array", f.Type) + return + } + v.fieldType = ptrType.Type + } + case "len": + lstrAddr, _ := v.toField(f) + lstrAddr.loadValue(loadSingleValue) + err = lstrAddr.Unreadable + if err == nil { + v.Len, _ = constant.Int64Val(lstrAddr.Value) + } + case "cap": + cstrAddr, _ := v.toField(f) + cstrAddr.loadValue(loadSingleValue) + err = cstrAddr.Unreadable + if err == nil { + v.Cap, _ = constant.Int64Val(cstrAddr.Value) + } + } + if err != nil { + v.Unreadable = err + return + } + } + + v.stride = v.fieldType.Size() + if t, ok := v.fieldType.(*dwarf.PtrType); ok { + v.stride = t.ByteSize + } + + return +} + +func (v *Variable) loadArrayValues(recurseLevel int, cfg LoadConfig) { + if v.Unreadable != nil { + return + } + if v.Len < 0 { + v.Unreadable = errors.New("Negative array length") + return + } + + count := v.Len + // Cap number of elements + if count > int64(cfg.MaxArrayValues) { + count = int64(cfg.MaxArrayValues) + } + + if v.stride < maxArrayStridePrefetch { + v.mem = cacheMemory(v.mem, v.Base, int(v.stride*count)) + } + + errcount := 0 + + for i := int64(0); i < count; i++ { + fieldvar := v.newVariable("", uintptr(int64(v.Base)+(i*v.stride)), v.fieldType) + fieldvar.loadValueInternal(recurseLevel+1, cfg) + + if fieldvar.Unreadable != nil { + errcount++ + } + + v.Children = append(v.Children, *fieldvar) + if errcount > maxErrCount { + break + } + } +} + +func (v *Variable) readComplex(size int64) { + var fs int64 + switch size { + case 8: + fs = 4 + case 16: + fs = 8 + default: + v.Unreadable = fmt.Errorf("invalid size (%d) for complex type", size) + return + } + + ftyp := &dwarf.FloatType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: fs, Name: fmt.Sprintf("float%d", fs)}, BitSize: fs * 8, BitOffset: 0}} + + realvar := v.newVariable("real", v.Addr, ftyp) + imagvar := v.newVariable("imaginary", v.Addr+uintptr(fs), ftyp) + realvar.loadValue(loadSingleValue) + imagvar.loadValue(loadSingleValue) + v.Value = constant.BinaryOp(realvar.Value, token.ADD, constant.MakeImag(imagvar.Value)) +} + +func (v *Variable) writeComplex(real, imag float64, size int64) error { + err := v.writeFloatRaw(real, int64(size/2)) + if err != nil { + return err + } + imagaddr := *v + imagaddr.Addr += uintptr(size / 2) + return imagaddr.writeFloatRaw(imag, int64(size/2)) +} + +func readIntRaw(mem memoryReadWriter, addr uintptr, size int64) (int64, error) { + var n int64 + + val, err := mem.readMemory(addr, int(size)) + if err != nil { + return 0, err + } + + switch size { + case 1: + n = int64(int8(val[0])) + case 2: + n = int64(int16(binary.LittleEndian.Uint16(val))) + case 4: + n = int64(int32(binary.LittleEndian.Uint32(val))) + case 8: + n = int64(binary.LittleEndian.Uint64(val)) + } + + return n, nil +} + +func (v *Variable) writeUint(value uint64, size int64) error { + val := make([]byte, size) + + switch size { + case 1: + val[0] = byte(value) + case 2: + binary.LittleEndian.PutUint16(val, uint16(value)) + case 4: + binary.LittleEndian.PutUint32(val, uint32(value)) + case 8: + binary.LittleEndian.PutUint64(val, uint64(value)) + } + + _, err := v.mem.writeMemory(v.Addr, val) + return err +} + +func readUintRaw(mem memoryReadWriter, addr uintptr, size int64) (uint64, error) { + var n uint64 + + val, err := mem.readMemory(addr, int(size)) + if err != nil { + return 0, err + } + + switch size { + case 1: + n = uint64(val[0]) + case 2: + n = uint64(binary.LittleEndian.Uint16(val)) + case 4: + n = uint64(binary.LittleEndian.Uint32(val)) + case 8: + n = uint64(binary.LittleEndian.Uint64(val)) + } + + return n, nil +} + +func (v *Variable) readFloatRaw(size int64) (float64, error) { + val, err := v.mem.readMemory(v.Addr, int(size)) + if err != nil { + return 0.0, err + } + buf := bytes.NewBuffer(val) + + switch size { + case 4: + n := float32(0) + binary.Read(buf, binary.LittleEndian, &n) + return float64(n), nil + case 8: + n := float64(0) + binary.Read(buf, binary.LittleEndian, &n) + return n, nil + } + + return 0.0, fmt.Errorf("could not read float") +} + +func (v *Variable) writeFloatRaw(f float64, size int64) error { + buf := bytes.NewBuffer(make([]byte, 0, size)) + + switch size { + case 4: + n := float32(f) + binary.Write(buf, binary.LittleEndian, n) + case 8: + n := float64(f) + binary.Write(buf, binary.LittleEndian, n) + } + + _, err := v.mem.writeMemory(v.Addr, buf.Bytes()) + return err +} + +func (v *Variable) writeBool(value bool) error { + val := []byte{0} + val[0] = *(*byte)(unsafe.Pointer(&value)) + _, err := v.mem.writeMemory(v.Addr, val) + return err +} + +func (v *Variable) readFunctionPtr() { + val, err := v.mem.readMemory(v.Addr, v.dbp.arch.PtrSize()) + if err != nil { + v.Unreadable = err + return + } + + // dereference pointer to find function pc + fnaddr := uintptr(binary.LittleEndian.Uint64(val)) + if fnaddr == 0 { + v.Base = 0 + v.Value = constant.MakeString("") + return + } + + val, err = v.mem.readMemory(fnaddr, v.dbp.arch.PtrSize()) + if err != nil { + v.Unreadable = err + return + } + + v.Base = uintptr(binary.LittleEndian.Uint64(val)) + fn := v.dbp.goSymTable.PCToFunc(uint64(v.Base)) + if fn == nil { + v.Unreadable = fmt.Errorf("could not find function for %#v", v.Base) + return + } + + v.Value = constant.MakeString(fn.Name) +} + +func (v *Variable) loadMap(recurseLevel int, cfg LoadConfig) { + it := v.mapIterator() + if it == nil { + return + } + + for skip := 0; skip < v.mapSkip; skip++ { + if ok := it.next(); !ok { + v.Unreadable = fmt.Errorf("map index out of bounds") + return + } + } + + count := 0 + errcount := 0 + for it.next() { + if count >= cfg.MaxArrayValues { + break + } + key := it.key() + val := it.value() + key.loadValueInternal(recurseLevel+1, cfg) + val.loadValueInternal(recurseLevel+1, cfg) + if key.Unreadable != nil || val.Unreadable != nil { + errcount++ + } + v.Children = append(v.Children, *key) + v.Children = append(v.Children, *val) + count++ + if errcount > maxErrCount { + break + } + } +} + +type mapIterator struct { + v *Variable + numbuckets uint64 + oldmask uint64 + buckets *Variable + oldbuckets *Variable + b *Variable + bidx uint64 + + tophashes *Variable + keys *Variable + values *Variable + overflow *Variable + + idx int64 +} + +// Code derived from go/src/runtime/hashmap.go +func (v *Variable) mapIterator() *mapIterator { + sv := v.clone() + sv.RealType = resolveTypedef(&(sv.RealType.(*dwarf.MapType).TypedefType)) + sv = sv.maybeDereference() + v.Base = sv.Addr + + maptype, ok := sv.RealType.(*dwarf.StructType) + if !ok { + v.Unreadable = fmt.Errorf("wrong real type for map") + return nil + } + + it := &mapIterator{v: v, bidx: 0, b: nil, idx: 0} + + if sv.Addr == 0 { + it.numbuckets = 0 + return it + } + + v.mem = cacheMemory(v.mem, v.Base, int(v.RealType.Size())) + + for _, f := range maptype.Field { + var err error + field, _ := sv.toField(f) + switch f.Name { + case "count": + v.Len, err = field.asInt() + case "B": + var b uint64 + b, err = field.asUint() + it.numbuckets = 1 << b + it.oldmask = (1 << (b - 1)) - 1 + case "buckets": + it.buckets = field.maybeDereference() + case "oldbuckets": + it.oldbuckets = field.maybeDereference() + } + if err != nil { + v.Unreadable = err + return nil + } + } + + if it.buckets.Kind != reflect.Struct || it.oldbuckets.Kind != reflect.Struct { + v.Unreadable = mapBucketsNotStructErr + return nil + } + + return it +} + +var mapBucketContentsNotArrayErr = errors.New("malformed map type: keys, values or tophash of a bucket is not an array") +var mapBucketContentsInconsistentLenErr = errors.New("malformed map type: inconsistent array length in bucket") +var mapBucketsNotStructErr = errors.New("malformed map type: buckets, oldbuckets or overflow field not a struct") + +func (it *mapIterator) nextBucket() bool { + if it.overflow != nil && it.overflow.Addr > 0 { + it.b = it.overflow + } else { + it.b = nil + + for it.bidx < it.numbuckets { + it.b = it.buckets.clone() + it.b.Addr += uintptr(uint64(it.buckets.DwarfType.Size()) * it.bidx) + + if it.oldbuckets.Addr <= 0 { + break + } + + // if oldbuckets is not nil we are iterating through a map that is in + // the middle of a grow. + // if the bucket we are looking at hasn't been filled in we iterate + // instead through its corresponding "oldbucket" (i.e. the bucket the + // elements of this bucket are coming from) but only if this is the first + // of the two buckets being created from the same oldbucket (otherwise we + // would print some keys twice) + + oldbidx := it.bidx & it.oldmask + oldb := it.oldbuckets.clone() + oldb.Addr += uintptr(uint64(it.oldbuckets.DwarfType.Size()) * oldbidx) + + if mapEvacuated(oldb) { + break + } + + if oldbidx == it.bidx { + it.b = oldb + break + } + + // oldbucket origin for current bucket has not been evacuated but we have already + // iterated over it so we should just skip it + it.b = nil + it.bidx++ + } + + if it.b == nil { + return false + } + it.bidx++ + } + + if it.b.Addr <= 0 { + return false + } + + it.b.mem = cacheMemory(it.b.mem, it.b.Addr, int(it.b.RealType.Size())) + + it.tophashes = nil + it.keys = nil + it.values = nil + it.overflow = nil + + for _, f := range it.b.DwarfType.(*dwarf.StructType).Field { + field, err := it.b.toField(f) + if err != nil { + it.v.Unreadable = err + return false + } + if field.Unreadable != nil { + it.v.Unreadable = field.Unreadable + return false + } + + switch f.Name { + case "tophash": + it.tophashes = field + case "keys": + it.keys = field + case "values": + it.values = field + case "overflow": + it.overflow = field.maybeDereference() + } + } + + // sanity checks + if it.tophashes == nil || it.keys == nil || it.values == nil { + it.v.Unreadable = fmt.Errorf("malformed map type") + return false + } + + if it.tophashes.Kind != reflect.Array || it.keys.Kind != reflect.Array || it.values.Kind != reflect.Array { + it.v.Unreadable = mapBucketContentsNotArrayErr + return false + } + + if it.tophashes.Len != it.keys.Len || it.tophashes.Len != it.values.Len { + it.v.Unreadable = mapBucketContentsInconsistentLenErr + return false + } + + if it.overflow.Kind != reflect.Struct { + it.v.Unreadable = mapBucketsNotStructErr + return false + } + + return true +} + +func (it *mapIterator) next() bool { + for { + if it.b == nil || it.idx >= it.tophashes.Len { + r := it.nextBucket() + if !r { + return false + } + it.idx = 0 + } + tophash, _ := it.tophashes.sliceAccess(int(it.idx)) + h, err := tophash.asUint() + if err != nil { + it.v.Unreadable = fmt.Errorf("unreadable tophash: %v", err) + return false + } + it.idx++ + if h != hashTophashEmpty { + return true + } + } +} + +func (it *mapIterator) key() *Variable { + k, _ := it.keys.sliceAccess(int(it.idx - 1)) + return k +} + +func (it *mapIterator) value() *Variable { + v, _ := it.values.sliceAccess(int(it.idx - 1)) + return v +} + +func mapEvacuated(b *Variable) bool { + if b.Addr == 0 { + return true + } + for _, f := range b.DwarfType.(*dwarf.StructType).Field { + if f.Name != "tophash" { + continue + } + tophashes, _ := b.toField(f) + tophash0var, _ := tophashes.sliceAccess(0) + tophash0, err := tophash0var.asUint() + if err != nil { + return true + } + return tophash0 > hashTophashEmpty && tophash0 < hashMinTopHash + } + return true +} + +func (v *Variable) loadInterface(recurseLevel int, loadData bool, cfg LoadConfig) { + var _type, typestring, data *Variable + var typ dwarf.Type + var err error + isnil := false + + // An interface variable is implemented either by a runtime.iface + // struct or a runtime.eface struct. The difference being that empty + // interfaces (i.e. "interface {}") are represented by runtime.eface + // and non-empty interfaces by runtime.iface. + // + // For both runtime.ifaces and runtime.efaces the data is stored in v.data + // + // The concrete type however is stored in v.tab._type for non-empty + // interfaces and in v._type for empty interfaces. + // + // For nil empty interface variables _type will be nil, for nil + // non-empty interface variables tab will be nil + // + // In either case the _type field is a pointer to a runtime._type struct. + // + // Before go1.7 _type used to have a field named 'string' containing + // the name of the type. Since go1.7 the field has been replaced by a + // str field that contains an offset in the module data, the concrete + // type must be calculated using the str address along with the value + // of v.tab._type (v._type for empty interfaces). + // + // The following code works for both runtime.iface and runtime.eface + // and sets the go17 flag when the 'string' field can not be found + // but the str field was found + + go17 := false + + v.mem = cacheMemory(v.mem, v.Addr, int(v.RealType.Size())) + + ityp := resolveTypedef(&v.RealType.(*dwarf.InterfaceType).TypedefType).(*dwarf.StructType) + + for _, f := range ityp.Field { + switch f.Name { + case "tab": // for runtime.iface + tab, _ := v.toField(f) + tab = tab.maybeDereference() + isnil = tab.Addr == 0 + if !isnil { + _type, err = tab.structMember("_type") + if err != nil { + v.Unreadable = fmt.Errorf("invalid interface type: %v", err) + return + } + typestring, err = _type.structMember("_string") + if err == nil { + typestring = typestring.maybeDereference() + } else { + go17 = true + } + } + case "_type": // for runtime.eface + _type, _ = v.toField(f) + _type = _type.maybeDereference() + isnil = _type.Addr == 0 + if !isnil { + typestring, err = _type.structMember("_string") + if err == nil { + typestring = typestring.maybeDereference() + } else { + go17 = true + } + } + case "data": + data, _ = v.toField(f) + } + } + + if isnil { + // interface to nil + data = data.maybeDereference() + v.Children = []Variable{*data} + if loadData { + v.Children[0].loadValueInternal(recurseLevel, cfg) + } + return + } + + if data == nil { + v.Unreadable = fmt.Errorf("invalid interface type") + return + } + + var kind int64 + + if go17 { + // No 'string' field use 'str' and 'runtime.firstmoduledata' to + // find out what the concrete type is + _type = _type.maybeDereference() + + var typename string + typename, kind, err = nameOfRuntimeType(_type) + if err != nil { + v.Unreadable = fmt.Errorf("invalid interface type: %v", err) + return + } + + typ, err = v.dbp.findType(typename) + if err != nil { + v.Unreadable = fmt.Errorf("interface type %q not found for %#x: %v", typename, data.Addr, err) + return + } + } else { + if typestring == nil || typestring.Addr == 0 || typestring.Kind != reflect.String { + v.Unreadable = fmt.Errorf("invalid interface type") + return + } + typestring.loadValue(LoadConfig{false, 0, 512, 0, 0}) + if typestring.Unreadable != nil { + v.Unreadable = fmt.Errorf("invalid interface type: %v", typestring.Unreadable) + return + } + + typename := constant.StringVal(typestring.Value) + + t, err := parser.ParseExpr(typename) + if err != nil { + v.Unreadable = fmt.Errorf("invalid interface type, unparsable data type: %v", err) + return + } + + typ, err = v.dbp.findTypeExpr(t) + if err != nil { + v.Unreadable = fmt.Errorf("interface type %q not found for %#x: %v", typename, data.Addr, err) + return + } + } + + if kind&kindDirectIface == 0 { + realtyp := resolveTypedef(typ) + if _, isptr := realtyp.(*dwarf.PtrType); !isptr { + typ = v.dbp.pointerTo(typ) + } + } + + data = data.newVariable("data", data.Addr, typ) + + v.Children = []Variable{*data} + if loadData && recurseLevel <= cfg.MaxVariableRecurse { + v.Children[0].loadValueInternal(recurseLevel, cfg) + } else { + v.Children[0].OnlyAddr = true + } + return +} + +// Fetches all variables of a specific type in the current function scope +func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg LoadConfig) ([]*Variable, error) { + reader := scope.DwarfReader() + off, err := scope.Thread.dbp.findFunctionDebugInfo(scope.PC) + if err != nil { + return nil, err + } + reader.Seek(off) + reader.Next() + + var vars []*Variable + for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() { + if err != nil { + return nil, err + } + if entry.Tag == 0 { + break + } + + if entry.Tag == tag { + val, err := scope.extractVariableFromEntry(entry, cfg) + if err != nil { + // skip variables that we can't parse yet + continue + } + + vars = append(vars, val) + } + } + if len(vars) <= 0 { + return vars, nil + } + + // prefetch the whole chunk of memory relative to these variables + + minaddr := vars[0].Addr + var maxaddr uintptr + var size int64 + + for _, v := range vars { + if v.Addr < minaddr { + minaddr = v.Addr + } + + size += v.DwarfType.Size() + + if end := v.Addr + uintptr(v.DwarfType.Size()); end > maxaddr { + maxaddr = end + } + } + + // check that we aren't trying to cache too much memory: we shouldn't + // exceed the real size of the variables by more than the number of + // variables times the size of an architecture pointer (to allow for memory + // alignment). + if int64(maxaddr-minaddr)-size <= int64(len(vars))*int64(scope.PtrSize()) { + mem := cacheMemory(vars[0].mem, minaddr, int(maxaddr-minaddr)) + + for _, v := range vars { + v.mem = mem + } + } + + for _, v := range vars { + v.loadValue(cfg) + } + + return vars, nil +} diff --git a/vendor/github.com/derekparker/delve/pkg/proc/zsyscall_windows.go b/vendor/github.com/derekparker/delve/pkg/proc/zsyscall_windows.go new file mode 100644 index 0000000..ee2b33c --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/proc/zsyscall_windows.go @@ -0,0 +1,181 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package proc + +import ( + "syscall" + "unsafe" +) + +var _ unsafe.Pointer + +var ( + modntdll = syscall.NewLazyDLL("ntdll.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread") + procGetThreadContext = modkernel32.NewProc("GetThreadContext") + procSetThreadContext = modkernel32.NewProc("SetThreadContext") + procSuspendThread = modkernel32.NewProc("SuspendThread") + procResumeThread = modkernel32.NewProc("ResumeThread") + procContinueDebugEvent = modkernel32.NewProc("ContinueDebugEvent") + procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory") + procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory") + procDebugBreakProcess = modkernel32.NewProc("DebugBreakProcess") + procWaitForDebugEvent = modkernel32.NewProc("WaitForDebugEvent") + procDebugActiveProcess = modkernel32.NewProc("DebugActiveProcess") + procDebugActiveProcessStop = modkernel32.NewProc("DebugActiveProcessStop") + procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW") +) + +func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) { + r0, _, _ := syscall.Syscall6(procNtQueryInformationThread.Addr(), 5, uintptr(threadHandle), uintptr(infoclass), uintptr(info), uintptr(infolen), uintptr(unsafe.Pointer(retlen)), 0) + status = _NTSTATUS(r0) + return +} + +func _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) { + r1, _, e1 := syscall.Syscall(procGetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) { + r1, _, e1 := syscall.Syscall(procSetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) { + r0, _, e1 := syscall.Syscall(procSuspendThread.Addr(), 1, uintptr(threadid), 0, 0) + prevsuspcount = uint32(r0) + if prevsuspcount == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) { + r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(threadid), 0, 0) + prevsuspcount = uint32(r0) + if prevsuspcount == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) { + r1, _, e1 := syscall.Syscall(procContinueDebugEvent.Addr(), 3, uintptr(processid), uintptr(threadid), uintptr(continuestatus)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(byteswritten)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(bytesread)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _DebugBreakProcess(process syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDebugBreakProcess.Addr(), 1, uintptr(process), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) { + r1, _, e1 := syscall.Syscall(procWaitForDebugEvent.Addr(), 2, uintptr(unsafe.Pointer(debugevent)), uintptr(milliseconds), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _DebugActiveProcess(processid uint32) (err error) { + r1, _, e1 := syscall.Syscall(procDebugActiveProcess.Addr(), 1, uintptr(processid), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _DebugActiveProcessStop(processid uint32) (err error) { + r1, _, e1 := syscall.Syscall(procDebugActiveProcessStop.Addr(), 1, uintptr(processid), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _QueryFullProcessImageName(process syscall.Handle, flags uint32, exename *uint16, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procQueryFullProcessImageNameW.Addr(), 4, uintptr(process), uintptr(flags), uintptr(unsafe.Pointer(exename)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/derekparker/delve/pkg/target/target.go b/vendor/github.com/derekparker/delve/pkg/target/target.go new file mode 100644 index 0000000..4455160 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/target/target.go @@ -0,0 +1,84 @@ +package target + +import ( + "debug/gosym" + "go/ast" + "time" + + "github.com/derekparker/delve/pkg/proc" +) + +// Target represents the target of the debugger. This +// target could be a system process, core file, etc. +type Interface interface { + Info + ProcessManipulation + BreakpointManipulation + VariableEval +} + +// Info is an interface that provides general information on the target. +type Info interface { + Pid() int + Exited() bool + Running() bool + + BinaryInfo + ThreadInfo + GoroutineInfo +} + +// BinaryInfo is an interface for accessing information on the binary file +// and the contents of binary sections. +type BinaryInfo interface { + LastModified() time.Time + Sources() map[string]*gosym.Obj + FindFileLocation(fileName string, lineNumber int) (uint64, error) + FindFunctionLocation(funcName string, firstLine bool, lineOffset int) (uint64, error) + Funcs() []gosym.Func + Types() ([]string, error) + PCToLine(uint64) (string, int, *gosym.Func) + FirstPCAfterPrologue(fn *gosym.Func, sameline bool) (uint64, error) +} + +// ThreadInfo is an interface for getting information on active threads +// in the process. +type ThreadInfo interface { + Threads() map[int]*proc.Thread + CurrentThread() *proc.Thread +} + +// GoroutineInfo is an interface for getting information on running goroutines. +type GoroutineInfo interface { + GoroutinesInfo() ([]*proc.G, error) + SelectedGoroutine() *proc.G + FindGoroutine(int) (*proc.G, error) +} + +// ProcessManipulation is an interface for changing the execution state of a process. +type ProcessManipulation interface { + Continue() error + Next() error + Step() error + StepOut() error + StepInstruction() error + SwitchThread(int) error + SwitchGoroutine(int) error + RequestManualStop() error + Halt() error + Kill() error + Detach(bool) error +} + +// BreakpointManipulation is an interface for managing breakpoints. +type BreakpointManipulation interface { + Breakpoints() map[uint64]*proc.Breakpoint + SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) + ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) + ClearInternalBreakpoints() error +} + +// VariableEval is an interface for dealing with eval scopes. +type VariableEval interface { + ConvertEvalScope(gid, frame int) (*proc.EvalScope, error) +} diff --git a/vendor/github.com/derekparker/delve/pkg/terminal/command.go b/vendor/github.com/derekparker/delve/pkg/terminal/command.go new file mode 100644 index 0000000..764c3e8 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/terminal/command.go @@ -0,0 +1,1426 @@ +// Package terminal implements functions for responding to user +// input and dispatching to appropriate backend commands. +package terminal + +import ( + "bufio" + "errors" + "fmt" + "go/parser" + "go/scanner" + "io" + "math" + "os" + "regexp" + "sort" + "strconv" + "strings" + "text/tabwriter" + + "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/api" + "github.com/derekparker/delve/service/debugger" +) + +type cmdPrefix int + +const ( + noPrefix = cmdPrefix(0) + scopePrefix = cmdPrefix(1 << iota) + onPrefix +) + +type callContext struct { + Prefix cmdPrefix + Scope api.EvalScope + Breakpoint *api.Breakpoint +} + +type cmdfunc func(t *Term, ctx callContext, args string) error + +type command struct { + aliases []string + allowedPrefixes cmdPrefix + helpMsg string + cmdFn cmdfunc +} + +// Returns true if the command string matches one of the aliases for this command +func (c command) match(cmdstr string) bool { + for _, v := range c.aliases { + if v == cmdstr { + return true + } + } + return false +} + +// Commands represents the commands for Delve terminal process. +type Commands struct { + cmds []command + lastCmd cmdfunc + client service.Client +} + +var ( + LongLoadConfig = api.LoadConfig{true, 1, 64, 64, -1} + ShortLoadConfig = api.LoadConfig{false, 0, 64, 0, 3} +) + +type ByFirstAlias []command + +func (a ByFirstAlias) Len() int { return len(a) } +func (a ByFirstAlias) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByFirstAlias) Less(i, j int) bool { return a[i].aliases[0] < a[j].aliases[0] } + +// DebugCommands returns a Commands struct with default commands defined. +func DebugCommands(client service.Client) *Commands { + c := &Commands{client: client} + + c.cmds = []command{ + {aliases: []string{"help", "h"}, cmdFn: c.help, helpMsg: `Prints the help message. + + help [command] + +Type "help" followed by the name of a command for more information about it.`}, + {aliases: []string{"break", "b"}, cmdFn: breakpoint, helpMsg: `Sets a breakpoint. + + break [name] + +See $GOPATH/src/github.com/derekparker/delve/Documentation/cli/locspec.md for the syntax of linespec. + +See also: "help on", "help cond" and "help clear"`}, + {aliases: []string{"trace", "t"}, cmdFn: tracepoint, helpMsg: `Set tracepoint. + + trace [name] + +A tracepoint is a breakpoint that does not stop the execution of the program, instead when the tracepoint is hit a notification is displayed. See $GOPATH/src/github.com/derekparker/delve/Documentation/cli/locspec.md for the syntax of linespec. + +See also: "help on", "help cond" and "help clear"`}, + {aliases: []string{"restart", "r"}, cmdFn: restart, helpMsg: "Restart process."}, + {aliases: []string{"continue", "c"}, cmdFn: cont, helpMsg: "Run until breakpoint or program termination."}, + {aliases: []string{"step", "s"}, allowedPrefixes: scopePrefix, cmdFn: step, helpMsg: "Single step through program."}, + {aliases: []string{"step-instruction", "si"}, allowedPrefixes: scopePrefix, cmdFn: stepInstruction, helpMsg: "Single step a single cpu instruction."}, + {aliases: []string{"next", "n"}, allowedPrefixes: scopePrefix, cmdFn: next, helpMsg: "Step over to next source line."}, + {aliases: []string{"stepout"}, allowedPrefixes: scopePrefix, cmdFn: stepout, helpMsg: "Step out of the current function."}, + {aliases: []string{"threads"}, cmdFn: threads, helpMsg: "Print out info for every traced thread."}, + {aliases: []string{"thread", "tr"}, cmdFn: thread, helpMsg: `Switch to the specified thread. + + thread `}, + {aliases: []string{"clear"}, cmdFn: clear, helpMsg: `Deletes breakpoint. + + clear `}, + {aliases: []string{"clearall"}, cmdFn: clearAll, helpMsg: `Deletes multiple breakpoints. + + clearall [] + +If called with the linespec argument it will delete all the breakpoints matching the linespec. If linespec is omitted all breakpoints are deleted.`}, + {aliases: []string{"goroutines"}, cmdFn: goroutines, helpMsg: `List program goroutines. + + goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)] + +Print out info for every goroutine. The flag controls what information is shown along with each goroutine: + + -u displays location of topmost stackframe in user code + -r displays location of topmost stackframe (including frames inside private runtime functions) + -g displays location of go instruction that created the goroutine + +If no flag is specified the default is -u.`}, + {aliases: []string{"goroutine"}, allowedPrefixes: onPrefix | scopePrefix, cmdFn: c.goroutine, helpMsg: `Shows or changes current goroutine + + goroutine + goroutine + goroutine + +Called without arguments it will show information about the current goroutine. +Called with a single argument it will switch to the specified goroutine. +Called with more arguments it will execute a command on the specified goroutine.`}, + {aliases: []string{"breakpoints", "bp"}, cmdFn: breakpoints, helpMsg: "Print out info for active breakpoints."}, + {aliases: []string{"print", "p"}, allowedPrefixes: onPrefix | scopePrefix, cmdFn: printVar, helpMsg: `Evaluate an expression. + + [goroutine ] [frame ] print + +See $GOPATH/src/github.com/derekparker/delve/Documentation/cli/expr.md for a description of supported expressions.`}, + {aliases: []string{"set"}, allowedPrefixes: scopePrefix, cmdFn: setVar, helpMsg: `Changes the value of a variable. + + [goroutine ] [frame ] set = + +See $GOPATH/src/github.com/derekparker/delve/Documentation/cli/expr.md for a description of supported expressions. Only numerical variables and pointers can be changed.`}, + {aliases: []string{"sources"}, cmdFn: sources, helpMsg: `Print list of source files. + + sources [] + +If regex is specified only the source files matching it will be returned.`}, + {aliases: []string{"funcs"}, cmdFn: funcs, helpMsg: `Print list of functions. + + funcs [] + +If regex is specified only the functions matching it will be returned.`}, + {aliases: []string{"types"}, cmdFn: types, helpMsg: `Print list of types + + types [] + +If regex is specified only the functions matching it will be returned.`}, + {aliases: []string{"args"}, allowedPrefixes: scopePrefix | onPrefix, cmdFn: args, helpMsg: `Print function arguments. + + [goroutine ] [frame ] args [-v] [] + +If regex is specified only function arguments with a name matching it will be returned. If -v is specified more information about each function argument will be shown.`}, + {aliases: []string{"locals"}, allowedPrefixes: scopePrefix | onPrefix, cmdFn: locals, helpMsg: `Print local variables. + + [goroutine ] [frame ] locals [-v] [] + +If regex is specified only local variables with a name matching it will be returned. If -v is specified more information about each local variable will be shown.`}, + {aliases: []string{"vars"}, cmdFn: vars, helpMsg: `Print package variables. + + vars [-v] [] + +If regex is specified only package variables with a name matching it will be returned. If -v is specified more information about each package variable will be shown.`}, + {aliases: []string{"regs"}, cmdFn: regs, helpMsg: `Print contents of CPU registers. + + regs [-a] + +Argument -a shows more registers.`}, + {aliases: []string{"exit", "quit", "q"}, cmdFn: exitCommand, helpMsg: "Exit the debugger."}, + {aliases: []string{"list", "ls"}, allowedPrefixes: scopePrefix, cmdFn: listCommand, helpMsg: `Show source code. + + [goroutine ] [frame ] list [] + +Show source around current point or provided linespec.`}, + {aliases: []string{"stack", "bt"}, allowedPrefixes: scopePrefix | onPrefix, cmdFn: stackCommand, helpMsg: `Print stack trace. + + [goroutine ] [frame ] stack [] [-full] + +If -full is specified every stackframe will be decorated by the value of its local variables and function arguments.`}, + {aliases: []string{"frame"}, allowedPrefixes: scopePrefix, cmdFn: c.frame, helpMsg: `Executes command on a different frame. + + frame .`}, + {aliases: []string{"source"}, cmdFn: c.sourceCommand, helpMsg: `Executes a file containing a list of delve commands + + source `}, + {aliases: []string{"disassemble", "disass"}, allowedPrefixes: scopePrefix, cmdFn: disassCommand, helpMsg: `Disassembler. + + [goroutine ] [frame ] disassemble [-a ] [-l ] + +If no argument is specified the function being executed in the selected stack frame will be executed. + + -a disassembles the specified address range + -l disassembles the specified function`}, + {aliases: []string{"on"}, cmdFn: c.onCmd, helpMsg: `Executes a command when a breakpoint is hit. + + on . + +Supported commands: print, stack and goroutine)`}, + {aliases: []string{"condition", "cond"}, cmdFn: conditionCmd, helpMsg: `Set breakpoint condition. + + condition . + +Specifies that the breakpoint or tracepoint should break only if the boolean expression is true.`}, + } + + sort.Sort(ByFirstAlias(c.cmds)) + return c +} + +// Register custom commands. Expects cf to be a func of type cmdfunc, +// returning only an error. +func (c *Commands) Register(cmdstr string, cf cmdfunc, helpMsg string) { + for _, v := range c.cmds { + if v.match(cmdstr) { + v.cmdFn = cf + return + } + } + + c.cmds = append(c.cmds, command{aliases: []string{cmdstr}, cmdFn: cf, helpMsg: helpMsg}) +} + +// Find will look up the command function for the given command input. +// If it cannot find the command it will default to noCmdAvailable(). +// If the command is an empty string it will replay the last command. +func (c *Commands) Find(cmdstr string, prefix cmdPrefix) cmdfunc { + // If use last command, if there was one. + if cmdstr == "" { + if c.lastCmd != nil { + return c.lastCmd + } + return nullCommand + } + + for _, v := range c.cmds { + if v.match(cmdstr) { + if prefix != noPrefix && v.allowedPrefixes&prefix == 0 { + continue + } + c.lastCmd = v.cmdFn + return v.cmdFn + } + } + + return noCmdAvailable +} + +func (c *Commands) CallWithContext(cmdstr, args string, t *Term, ctx callContext) error { + return c.Find(cmdstr, ctx.Prefix)(t, ctx, args) +} + +func (c *Commands) Call(cmdstr, args string, t *Term) error { + ctx := callContext{Prefix: noPrefix, Scope: api.EvalScope{GoroutineID: -1, Frame: 0}} + return c.CallWithContext(cmdstr, args, t, ctx) +} + +// Merge takes aliases defined in the config struct and merges them with the default aliases. +func (c *Commands) Merge(allAliases map[string][]string) { + for i := range c.cmds { + if aliases, ok := allAliases[c.cmds[i].aliases[0]]; ok { + c.cmds[i].aliases = append(c.cmds[i].aliases, aliases...) + } + } +} + +var noCmdError = errors.New("command not available") + +func noCmdAvailable(t *Term, ctx callContext, args string) error { + return noCmdError +} + +func nullCommand(t *Term, ctx callContext, args string) error { + return nil +} + +func (c *Commands) help(t *Term, ctx callContext, args string) error { + if args != "" { + for _, cmd := range c.cmds { + for _, alias := range cmd.aliases { + if alias == args { + fmt.Println(cmd.helpMsg) + return nil + } + } + } + return noCmdError + } + + fmt.Println("The following commands are available:") + w := new(tabwriter.Writer) + w.Init(os.Stdout, 0, 8, 0, '-', 0) + for _, cmd := range c.cmds { + h := cmd.helpMsg + if idx := strings.Index(h, "\n"); idx >= 0 { + h = h[:idx] + } + if len(cmd.aliases) > 1 { + fmt.Fprintf(w, " %s (alias: %s) \t %s\n", cmd.aliases[0], strings.Join(cmd.aliases[1:], " | "), h) + } else { + fmt.Fprintf(w, " %s \t %s\n", cmd.aliases[0], h) + } + } + if err := w.Flush(); err != nil { + return err + } + fmt.Println("Type help followed by a command for full documentation.") + return nil +} + +type byThreadID []*api.Thread + +func (a byThreadID) Len() int { return len(a) } +func (a byThreadID) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byThreadID) Less(i, j int) bool { return a[i].ID < a[j].ID } + +func threads(t *Term, ctx callContext, args string) error { + threads, err := t.client.ListThreads() + if err != nil { + return err + } + state, err := t.client.GetState() + if err != nil { + return err + } + sort.Sort(byThreadID(threads)) + for _, th := range threads { + prefix := " " + if state.CurrentThread != nil && state.CurrentThread.ID == th.ID { + prefix = "* " + } + if th.Function != nil { + fmt.Printf("%sThread %d at %#v %s:%d %s\n", + prefix, th.ID, th.PC, ShortenFilePath(th.File), + th.Line, th.Function.Name) + } else { + fmt.Printf("%sThread %s\n", prefix, formatThread(th)) + } + } + return nil +} + +func thread(t *Term, ctx callContext, args string) error { + if len(args) == 0 { + return fmt.Errorf("you must specify a thread") + } + tid, err := strconv.Atoi(args) + if err != nil { + return err + } + oldState, err := t.client.GetState() + if err != nil { + return err + } + newState, err := t.client.SwitchThread(tid) + if err != nil { + return err + } + + oldThread := "" + newThread := "" + if oldState.CurrentThread != nil { + oldThread = strconv.Itoa(oldState.CurrentThread.ID) + } + if newState.CurrentThread != nil { + newThread = strconv.Itoa(newState.CurrentThread.ID) + } + fmt.Printf("Switched from %s to %s\n", oldThread, newThread) + return nil +} + +type byGoroutineID []*api.Goroutine + +func (a byGoroutineID) Len() int { return len(a) } +func (a byGoroutineID) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byGoroutineID) Less(i, j int) bool { return a[i].ID < a[j].ID } + +func goroutines(t *Term, ctx callContext, argstr string) error { + args := strings.Split(argstr, " ") + var fgl = fglUserCurrent + + switch len(args) { + case 0: + // nothing to do + case 1: + switch args[0] { + case "-u": + fgl = fglUserCurrent + case "-r": + fgl = fglRuntimeCurrent + case "-g": + fgl = fglGo + case "": + // nothing to do + default: + return fmt.Errorf("wrong argument: '%s'", args[0]) + } + default: + return fmt.Errorf("too many arguments") + } + state, err := t.client.GetState() + if err != nil { + return err + } + gs, err := t.client.ListGoroutines() + if err != nil { + return err + } + sort.Sort(byGoroutineID(gs)) + fmt.Printf("[%d goroutines]\n", len(gs)) + for _, g := range gs { + prefix := " " + if state.SelectedGoroutine != nil && g.ID == state.SelectedGoroutine.ID { + prefix = "* " + } + fmt.Printf("%sGoroutine %s\n", prefix, formatGoroutine(g, fgl)) + } + return nil +} + +func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error { + args := strings.SplitN(argstr, " ", 3) + + if ctx.Prefix == onPrefix { + if len(args) != 1 || args[0] != "" { + return errors.New("too many arguments to goroutine") + } + ctx.Breakpoint.Goroutine = true + return nil + } + + switch len(args) { + case 1: + if ctx.Prefix == scopePrefix { + return errors.New("no command passed to goroutine") + } + if args[0] == "" { + return printscope(t) + } + gid, err := strconv.Atoi(argstr) + if err != nil { + return err + } + + oldState, err := t.client.GetState() + if err != nil { + return err + } + newState, err := t.client.SwitchGoroutine(gid) + if err != nil { + return err + } + + fmt.Printf("Switched from %d to %d (thread %d)\n", oldState.SelectedGoroutine.ID, gid, newState.CurrentThread.ID) + return nil + case 2: + args = append(args, "") + } + + var err error + ctx.Prefix = scopePrefix + ctx.Scope.GoroutineID, err = strconv.Atoi(args[0]) + if err != nil { + return err + } + return c.CallWithContext(args[1], args[2], t, ctx) +} + +func (c *Commands) frame(t *Term, ctx callContext, args string) error { + v := strings.SplitN(args, " ", 3) + + switch len(v) { + case 0, 1: + return errors.New("not enough arguments") + case 2: + v = append(v, "") + } + + var err error + ctx.Prefix = scopePrefix + ctx.Scope.Frame, err = strconv.Atoi(v[0]) + if err != nil { + return err + } + return c.CallWithContext(v[1], v[2], t, ctx) +} + +func printscope(t *Term) error { + state, err := t.client.GetState() + if err != nil { + return err + } + + fmt.Printf("Thread %s\n", formatThread(state.CurrentThread)) + if state.SelectedGoroutine != nil { + writeGoroutineLong(os.Stdout, state.SelectedGoroutine, "") + } + return nil +} + +func formatThread(th *api.Thread) string { + if th == nil { + return "" + } + return fmt.Sprintf("%d at %s:%d", th.ID, ShortenFilePath(th.File), th.Line) +} + +type formatGoroutineLoc int + +const ( + fglRuntimeCurrent = formatGoroutineLoc(iota) + fglUserCurrent + fglGo +) + +func formatLocation(loc api.Location) string { + fname := "" + if loc.Function != nil { + fname = loc.Function.Name + } + return fmt.Sprintf("%s:%d %s (%#v)", ShortenFilePath(loc.File), loc.Line, fname, loc.PC) +} + +func formatGoroutine(g *api.Goroutine, fgl formatGoroutineLoc) string { + if g == nil { + return "" + } + var locname string + var loc api.Location + switch fgl { + case fglRuntimeCurrent: + locname = "Runtime" + loc = g.CurrentLoc + case fglUserCurrent: + locname = "User" + loc = g.UserCurrentLoc + case fglGo: + locname = "Go" + loc = g.GoStatementLoc + } + thread := "" + if g.ThreadID != 0 { + thread = fmt.Sprintf(" (thread %d)", g.ThreadID) + } + return fmt.Sprintf("%d - %s: %s%s", g.ID, locname, formatLocation(loc), thread) +} + +func writeGoroutineLong(w io.Writer, g *api.Goroutine, prefix string) { + fmt.Fprintf(w, "%sGoroutine %d:\n%s\tRuntime: %s\n%s\tUser: %s\n%s\tGo: %s\n", + prefix, g.ID, + prefix, formatLocation(g.CurrentLoc), + prefix, formatLocation(g.UserCurrentLoc), + prefix, formatLocation(g.GoStatementLoc)) +} + +func restart(t *Term, ctx callContext, args string) error { + discarded, err := t.client.Restart() + if err != nil { + return err + } + fmt.Println("Process restarted with PID", t.client.ProcessPid()) + for i := range discarded { + fmt.Printf("Discarded %s at %s: %v\n", formatBreakpointName(discarded[i].Breakpoint, false), formatBreakpointLocation(discarded[i].Breakpoint), discarded[i].Reason) + } + return nil +} + +func cont(t *Term, ctx callContext, args string) error { + stateChan := t.client.Continue() + var state *api.DebuggerState + for state = range stateChan { + if state.Err != nil { + return state.Err + } + printcontext(t, state) + } + printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true) + return nil +} + +func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string) error { + if !state.NextInProgress { + printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true) + return nil + } + for { + stateChan := t.client.Continue() + var state *api.DebuggerState + for state = range stateChan { + if state.Err != nil { + return state.Err + } + printcontext(t, state) + } + if !state.NextInProgress { + printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true) + return nil + } + fmt.Printf("\tbreakpoint hit during %s, continuing...\n", op) + } +} + +func scopePrefixSwitch(t *Term, ctx callContext) error { + if ctx.Prefix != scopePrefix { + return nil + } + if ctx.Scope.Frame != 0 { + return errors.New("frame prefix not accepted") + } + if ctx.Scope.GoroutineID > 0 { + _, err := t.client.SwitchGoroutine(ctx.Scope.GoroutineID) + if err != nil { + return err + } + } + return nil +} + +func step(t *Term, ctx callContext, args string) error { + if err := scopePrefixSwitch(t, ctx); err != nil { + return err + } + state, err := t.client.Step() + if err != nil { + return err + } + printcontext(t, state) + return continueUntilCompleteNext(t, state, "step") +} + +func stepInstruction(t *Term, ctx callContext, args string) error { + if err := scopePrefixSwitch(t, ctx); err != nil { + return err + } + state, err := t.client.StepInstruction() + if err != nil { + return err + } + printcontext(t, state) + printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true) + return nil +} + +func next(t *Term, ctx callContext, args string) error { + if err := scopePrefixSwitch(t, ctx); err != nil { + return err + } + state, err := t.client.Next() + if err != nil { + return err + } + printcontext(t, state) + return continueUntilCompleteNext(t, state, "next") +} + +func stepout(t *Term, ctx callContext, args string) error { + if err := scopePrefixSwitch(t, ctx); err != nil { + return err + } + state, err := t.client.StepOut() + if err != nil { + return err + } + printcontext(t, state) + return continueUntilCompleteNext(t, state, "stepout") +} + +func clear(t *Term, ctx callContext, args string) error { + if len(args) == 0 { + return fmt.Errorf("not enough arguments") + } + id, err := strconv.Atoi(args) + var bp *api.Breakpoint + if err == nil { + bp, err = t.client.ClearBreakpoint(id) + } else { + bp, err = t.client.ClearBreakpointByName(args) + } + if err != nil { + return err + } + fmt.Printf("%s cleared at %s\n", formatBreakpointName(bp, true), formatBreakpointLocation(bp)) + return nil +} + +func clearAll(t *Term, ctx callContext, args string) error { + breakPoints, err := t.client.ListBreakpoints() + if err != nil { + return err + } + + var locPCs map[uint64]struct{} + if args != "" { + locs, err := t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, args) + if err != nil { + return err + } + locPCs = make(map[uint64]struct{}) + for _, loc := range locs { + locPCs[loc.PC] = struct{}{} + } + } + + for _, bp := range breakPoints { + if locPCs != nil { + if _, ok := locPCs[bp.Addr]; !ok { + continue + } + } + + if bp.ID < 0 { + continue + } + + _, err := t.client.ClearBreakpoint(bp.ID) + if err != nil { + fmt.Printf("Couldn't delete %s at %s: %s\n", formatBreakpointName(bp, false), formatBreakpointLocation(bp), err) + } + fmt.Printf("%s cleared at %s\n", formatBreakpointName(bp, true), formatBreakpointLocation(bp)) + } + return nil +} + +// ByID sorts breakpoints by ID. +type ByID []*api.Breakpoint + +func (a ByID) Len() int { return len(a) } +func (a ByID) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByID) Less(i, j int) bool { return a[i].ID < a[j].ID } + +func breakpoints(t *Term, ctx callContext, args string) error { + breakPoints, err := t.client.ListBreakpoints() + if err != nil { + return err + } + sort.Sort(ByID(breakPoints)) + for _, bp := range breakPoints { + fmt.Printf("%s at %v (%d)\n", formatBreakpointName(bp, true), formatBreakpointLocation(bp), bp.TotalHitCount) + + var attrs []string + if bp.Cond != "" { + attrs = append(attrs, fmt.Sprintf("\tcond %s", bp.Cond)) + } + if bp.Stacktrace > 0 { + attrs = append(attrs, fmt.Sprintf("\tstack %d", bp.Stacktrace)) + } + if bp.Goroutine { + attrs = append(attrs, "\tgoroutine") + } + if bp.LoadArgs != nil { + if *(bp.LoadArgs) == LongLoadConfig { + attrs = append(attrs, "\targs -v") + } else { + attrs = append(attrs, "\targs") + } + } + if bp.LoadLocals != nil { + if *(bp.LoadLocals) == LongLoadConfig { + attrs = append(attrs, "\tlocals -v") + } else { + attrs = append(attrs, "\tlocals") + } + } + for i := range bp.Variables { + attrs = append(attrs, fmt.Sprintf("\tprint %s", bp.Variables[i])) + } + if len(attrs) > 0 { + fmt.Printf("%s\n", strings.Join(attrs, "\n")) + } + } + return nil +} + +func setBreakpoint(t *Term, tracepoint bool, argstr string) error { + args := strings.SplitN(argstr, " ", 2) + + requestedBp := &api.Breakpoint{} + locspec := "" + switch len(args) { + case 1: + locspec = argstr + case 2: + if api.ValidBreakpointName(args[0]) == nil { + requestedBp.Name = args[0] + locspec = args[1] + } else { + locspec = argstr + } + default: + return fmt.Errorf("address required") + } + + requestedBp.Tracepoint = tracepoint + locs, err := t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, locspec) + if err != nil { + if requestedBp.Name == "" { + return err + } + requestedBp.Name = "" + locspec = argstr + var err2 error + locs, err2 = t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, locspec) + if err2 != nil { + return err + } + } + for _, loc := range locs { + requestedBp.Addr = loc.PC + + bp, err := t.client.CreateBreakpoint(requestedBp) + if err != nil { + return err + } + + fmt.Printf("%s set at %s\n", formatBreakpointName(bp, true), formatBreakpointLocation(bp)) + } + return nil +} + +func breakpoint(t *Term, ctx callContext, args string) error { + return setBreakpoint(t, false, args) +} + +func tracepoint(t *Term, ctx callContext, args string) error { + return setBreakpoint(t, true, args) +} + +func printVar(t *Term, ctx callContext, args string) error { + if len(args) == 0 { + return fmt.Errorf("not enough arguments") + } + if ctx.Prefix == onPrefix { + ctx.Breakpoint.Variables = append(ctx.Breakpoint.Variables, args) + return nil + } + val, err := t.client.EvalVariable(ctx.Scope, args, LongLoadConfig) + if err != nil { + return err + } + + fmt.Println(val.MultilineString("")) + return nil +} + +func setVar(t *Term, ctx callContext, args string) error { + // HACK: in go '=' is not an operator, we detect the error and try to recover from it by splitting the input string + _, err := parser.ParseExpr(args) + if err == nil { + return fmt.Errorf("syntax error '=' not found") + } + + el, ok := err.(scanner.ErrorList) + if !ok || el[0].Msg != "expected '==', found '='" { + return err + } + + lexpr := args[:el[0].Pos.Offset] + rexpr := args[el[0].Pos.Offset+1:] + return t.client.SetVariable(ctx.Scope, lexpr, rexpr) +} + +func printFilteredVariables(varType string, vars []api.Variable, filter string, cfg api.LoadConfig) error { + reg, err := regexp.Compile(filter) + if err != nil { + return err + } + match := false + for _, v := range vars { + if reg == nil || reg.Match([]byte(v.Name)) { + match = true + if cfg == ShortLoadConfig { + fmt.Printf("%s = %s\n", v.Name, v.SinglelineString()) + } else { + fmt.Printf("%s = %s\n", v.Name, v.MultilineString("")) + } + } + } + if !match { + fmt.Printf("(no %s)\n", varType) + } + return nil +} + +func printSortedStrings(v []string, err error) error { + if err != nil { + return err + } + sort.Strings(v) + for _, d := range v { + fmt.Println(d) + } + return nil +} + +func sources(t *Term, ctx callContext, args string) error { + return printSortedStrings(t.client.ListSources(args)) +} + +func funcs(t *Term, ctx callContext, args string) error { + return printSortedStrings(t.client.ListFunctions(args)) +} + +func types(t *Term, ctx callContext, args string) error { + return printSortedStrings(t.client.ListTypes(args)) +} + +func parseVarArguments(args string) (filter string, cfg api.LoadConfig) { + if v := strings.SplitN(args, " ", 2); len(v) >= 1 && v[0] == "-v" { + if len(v) == 2 { + return v[1], LongLoadConfig + } else { + return "", LongLoadConfig + } + } + return args, ShortLoadConfig +} + +func args(t *Term, ctx callContext, args string) error { + filter, cfg := parseVarArguments(args) + if ctx.Prefix == onPrefix { + if filter != "" { + return fmt.Errorf("filter not supported on breakpoint") + } + ctx.Breakpoint.LoadArgs = &cfg + return nil + } + vars, err := t.client.ListFunctionArgs(ctx.Scope, cfg) + if err != nil { + return err + } + return printFilteredVariables("args", vars, filter, cfg) +} + +func locals(t *Term, ctx callContext, args string) error { + filter, cfg := parseVarArguments(args) + if ctx.Prefix == onPrefix { + if filter != "" { + return fmt.Errorf("filter not supported on breakpoint") + } + ctx.Breakpoint.LoadLocals = &cfg + return nil + } + locals, err := t.client.ListLocalVariables(ctx.Scope, cfg) + if err != nil { + return err + } + return printFilteredVariables("locals", locals, filter, cfg) +} + +func vars(t *Term, ctx callContext, args string) error { + filter, cfg := parseVarArguments(args) + vars, err := t.client.ListPackageVariables(filter, cfg) + if err != nil { + return err + } + return printFilteredVariables("vars", vars, filter, cfg) +} + +func regs(t *Term, ctx callContext, args string) error { + includeFp := false + if args == "-a" { + includeFp = true + } + regs, err := t.client.ListRegisters(0, includeFp) + if err != nil { + return err + } + fmt.Println(regs) + return nil +} + +func stackCommand(t *Term, ctx callContext, args string) error { + depth, full, err := parseStackArgs(args) + if err != nil { + return err + } + if ctx.Prefix == onPrefix { + ctx.Breakpoint.Stacktrace = depth + return nil + } + var cfg *api.LoadConfig + if full { + cfg = &ShortLoadConfig + } + stack, err := t.client.Stacktrace(ctx.Scope.GoroutineID, depth, cfg) + if err != nil { + return err + } + printStack(stack, "") + return nil +} + +func parseStackArgs(argstr string) (int, bool, error) { + var ( + depth = 10 + full = false + ) + if argstr != "" { + args := strings.Split(argstr, " ") + for i := range args { + if args[i] == "-full" { + full = true + } else { + n, err := strconv.Atoi(args[i]) + if err != nil { + return 0, false, fmt.Errorf("depth must be a number") + } + depth = n + } + } + } + return depth, full, nil +} + +func listCommand(t *Term, ctx callContext, args string) error { + if ctx.Prefix == scopePrefix { + locs, err := t.client.Stacktrace(ctx.Scope.GoroutineID, ctx.Scope.Frame, nil) + if err != nil { + return err + } + if ctx.Scope.Frame >= len(locs) { + return fmt.Errorf("Frame %d does not exist in goroutine %d", ctx.Scope.Frame, ctx.Scope.GoroutineID) + } + loc := locs[ctx.Scope.Frame] + return printfile(t, loc.File, loc.Line, true) + } + + if len(args) == 0 { + state, err := t.client.GetState() + if err != nil { + return err + } + printcontext(t, state) + printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true) + return nil + } + + locs, err := t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, args) + if err != nil { + return err + } + if len(locs) > 1 { + return debugger.AmbiguousLocationError{Location: args, CandidatesLocation: locs} + } + printfile(t, locs[0].File, locs[0].Line, false) + return nil +} + +func (c *Commands) sourceCommand(t *Term, ctx callContext, args string) error { + if len(args) == 0 { + return fmt.Errorf("wrong number of arguments: source ") + } + + return c.executeFile(t, args) +} + +var disasmUsageError = errors.New("wrong number of arguments: disassemble [-a ] [-l ]") + +func disassCommand(t *Term, ctx callContext, args string) error { + var cmd, rest string + + if args != "" { + argv := strings.SplitN(args, " ", 2) + if len(argv) != 2 { + return disasmUsageError + } + cmd = argv[0] + rest = argv[1] + } + + var disasm api.AsmInstructions + var disasmErr error + + switch cmd { + case "": + locs, err := t.client.FindLocation(ctx.Scope, "+0") + if err != nil { + return err + } + disasm, disasmErr = t.client.DisassemblePC(ctx.Scope, locs[0].PC, api.IntelFlavour) + case "-a": + v := strings.SplitN(rest, " ", 2) + if len(v) != 2 { + return disasmUsageError + } + startpc, err := strconv.ParseInt(v[0], 0, 64) + if err != nil { + return fmt.Errorf("wrong argument: %s is not a number", v[0]) + } + endpc, err := strconv.ParseInt(v[1], 0, 64) + if err != nil { + return fmt.Errorf("wrong argument: %s is not a number", v[1]) + } + disasm, disasmErr = t.client.DisassembleRange(ctx.Scope, uint64(startpc), uint64(endpc), api.IntelFlavour) + case "-l": + locs, err := t.client.FindLocation(ctx.Scope, rest) + if err != nil { + return err + } + if len(locs) != 1 { + return errors.New("expression specifies multiple locations") + } + disasm, disasmErr = t.client.DisassemblePC(ctx.Scope, locs[0].PC, api.IntelFlavour) + default: + return disasmUsageError + } + + if disasmErr != nil { + return disasmErr + } + + fmt.Printf("printing\n") + DisasmPrint(disasm, os.Stdout) + + return nil +} + +func digits(n int) int { + if n <= 0 { + return 1 + } + return int(math.Floor(math.Log10(float64(n)))) + 1 +} + +func printStack(stack []api.Stackframe, ind string) { + if len(stack) == 0 { + return + } + d := digits(len(stack) - 1) + fmtstr := "%s%" + strconv.Itoa(d) + "d 0x%016x in %s\n" + s := ind + strings.Repeat(" ", d+2+len(ind)) + + for i := range stack { + name := "(nil)" + if stack[i].Function != nil { + name = stack[i].Function.Name + } + fmt.Printf(fmtstr, ind, i, stack[i].PC, name) + fmt.Printf("%sat %s:%d\n", s, ShortenFilePath(stack[i].File), stack[i].Line) + + for j := range stack[i].Arguments { + fmt.Printf("%s %s = %s\n", s, stack[i].Arguments[j].Name, stack[i].Arguments[j].SinglelineString()) + } + for j := range stack[i].Locals { + fmt.Printf("%s %s = %s\n", s, stack[i].Locals[j].Name, stack[i].Locals[j].SinglelineString()) + } + } +} + +func printcontext(t *Term, state *api.DebuggerState) error { + for i := range state.Threads { + if (state.CurrentThread != nil) && (state.Threads[i].ID == state.CurrentThread.ID) { + continue + } + if state.Threads[i].Breakpoint != nil { + printcontextThread(t, state.Threads[i]) + } + } + + if state.CurrentThread == nil { + fmt.Println("No current thread available") + return nil + } + if len(state.CurrentThread.File) == 0 { + fmt.Printf("Stopped at: 0x%x\n", state.CurrentThread.PC) + t.Println("=>", "no source available") + return nil + } + + printcontextThread(t, state.CurrentThread) + + return nil +} + +func printcontextThread(t *Term, th *api.Thread) { + fn := th.Function + + if th.Breakpoint == nil { + fmt.Printf("> %s() %s:%d (PC: %#v)\n", fn.Name, ShortenFilePath(th.File), th.Line, th.PC) + return + } + + args := "" + if th.BreakpointInfo != nil && th.Breakpoint.LoadArgs != nil && *th.Breakpoint.LoadArgs == ShortLoadConfig { + var arg []string + for _, ar := range th.BreakpointInfo.Arguments { + arg = append(arg, ar.SinglelineString()) + } + args = strings.Join(arg, ", ") + } + + bpname := "" + if th.Breakpoint.Name != "" { + bpname = fmt.Sprintf("[%s] ", th.Breakpoint.Name) + } + + if hitCount, ok := th.Breakpoint.HitCount[strconv.Itoa(th.GoroutineID)]; ok { + fmt.Printf("> %s%s(%s) %s:%d (hits goroutine(%d):%d total:%d) (PC: %#v)\n", + bpname, + fn.Name, + args, + ShortenFilePath(th.File), + th.Line, + th.GoroutineID, + hitCount, + th.Breakpoint.TotalHitCount, + th.PC) + } else { + fmt.Printf("> %s%s(%s) %s:%d (hits total:%d) (PC: %#v)\n", + bpname, + fn.Name, + args, + ShortenFilePath(th.File), + th.Line, + th.Breakpoint.TotalHitCount, + th.PC) + } + + if th.BreakpointInfo != nil { + bp := th.Breakpoint + bpi := th.BreakpointInfo + + if bpi.Goroutine != nil { + writeGoroutineLong(os.Stdout, bpi.Goroutine, "\t") + } + + for _, v := range bpi.Variables { + fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t")) + } + + for _, v := range bpi.Locals { + if *bp.LoadLocals == LongLoadConfig { + fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t")) + } else { + fmt.Printf("\t%s: %s\n", v.Name, v.SinglelineString()) + } + } + + if bp.LoadArgs != nil && *bp.LoadArgs == LongLoadConfig { + for _, v := range bpi.Arguments { + fmt.Printf("\t%s: %s\n", v.Name, v.MultilineString("\t")) + } + } + + if bpi.Stacktrace != nil { + fmt.Printf("\tStack:\n") + printStack(bpi.Stacktrace, "\t\t") + } + } +} + +func printfile(t *Term, filename string, line int, showArrow bool) error { + file, err := os.Open(t.substitutePath(filename)) + if err != nil { + return err + } + defer file.Close() + + fi, _ := file.Stat() + lastModExe := t.client.LastModified() + if fi.ModTime().After(lastModExe) { + fmt.Println("Warning: listing may not match stale executable") + } + + buf := bufio.NewScanner(file) + l := line + for i := 1; i < l-5; i++ { + if !buf.Scan() { + return nil + } + } + + s := l - 5 + if s < 1 { + s = 1 + } + + for i := s; i <= l+5; i++ { + if !buf.Scan() { + return nil + } + + var prefix string + if showArrow { + prefix = " " + if i == l { + prefix = "=>" + } + } + + prefix = fmt.Sprintf("%s%4d:\t", prefix, i) + t.Println(prefix, buf.Text()) + } + return nil +} + +// ExitRequestError is returned when the user +// exits Delve. +type ExitRequestError struct{} + +func (ere ExitRequestError) Error() string { + return "" +} + +func exitCommand(t *Term, ctx callContext, args string) error { + return ExitRequestError{} +} + +func getBreakpointByIDOrName(t *Term, arg string) (*api.Breakpoint, error) { + if id, err := strconv.Atoi(arg); err == nil { + return t.client.GetBreakpoint(id) + } + return t.client.GetBreakpointByName(arg) +} + +func (c *Commands) onCmd(t *Term, ctx callContext, argstr string) error { + args := strings.SplitN(argstr, " ", 3) + + if len(args) < 2 { + return errors.New("not enough arguments") + } + + if len(args) < 3 { + args = append(args, "") + } + + bp, err := getBreakpointByIDOrName(t, args[0]) + if err != nil { + return err + } + + ctx.Prefix = onPrefix + ctx.Breakpoint = bp + err = c.CallWithContext(args[1], args[2], t, ctx) + if err != nil { + return err + } + return t.client.AmendBreakpoint(ctx.Breakpoint) +} + +func conditionCmd(t *Term, ctx callContext, argstr string) error { + args := strings.SplitN(argstr, " ", 2) + + if len(args) < 2 { + return fmt.Errorf("not enough arguments") + } + + bp, err := getBreakpointByIDOrName(t, args[0]) + if err != nil { + return err + } + bp.Cond = args[1] + + return t.client.AmendBreakpoint(bp) +} + +// ShortenFilePath take a full file path and attempts to shorten +// it by replacing the current directory to './'. +func ShortenFilePath(fullPath string) string { + workingDir, _ := os.Getwd() + return strings.Replace(fullPath, workingDir, ".", 1) +} + +func (c *Commands) executeFile(t *Term, name string) error { + fh, err := os.Open(name) + if err != nil { + return err + } + defer fh.Close() + + scanner := bufio.NewScanner(fh) + lineno := 0 + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + lineno++ + + if line == "" || line[0] == '#' { + continue + } + + cmdstr, args := parseCommand(line) + + if err := c.Call(cmdstr, args, t); err != nil { + fmt.Printf("%s:%d: %v\n", name, lineno, err) + } + } + + return scanner.Err() +} + +func formatBreakpointName(bp *api.Breakpoint, upcase bool) string { + thing := "breakpoint" + if bp.Tracepoint { + thing = "tracepoint" + } + if upcase { + thing = strings.Title(thing) + } + id := bp.Name + if id == "" { + id = strconv.Itoa(bp.ID) + } + return fmt.Sprintf("%s %s", thing, id) +} + +func formatBreakpointLocation(bp *api.Breakpoint) string { + p := ShortenFilePath(bp.File) + if bp.FunctionName != "" { + return fmt.Sprintf("%#v for %s() %s:%d", bp.Addr, bp.FunctionName, p, bp.Line) + } + return fmt.Sprintf("%#v for %s:%d", bp.Addr, p, bp.Line) +} diff --git a/vendor/github.com/derekparker/delve/pkg/terminal/disasmprint.go b/vendor/github.com/derekparker/delve/pkg/terminal/disasmprint.go new file mode 100644 index 0000000..7c27374 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/terminal/disasmprint.go @@ -0,0 +1,31 @@ +package terminal + +import ( + "bufio" + "fmt" + "github.com/derekparker/delve/service/api" + "io" + "path/filepath" + "text/tabwriter" +) + +func DisasmPrint(dv api.AsmInstructions, out io.Writer) { + bw := bufio.NewWriter(out) + defer bw.Flush() + if len(dv) > 0 && dv[0].Loc.Function != nil { + fmt.Fprintf(bw, "TEXT %s(SB) %s\n", dv[0].Loc.Function.Name, dv[0].Loc.File) + } + tw := tabwriter.NewWriter(bw, 1, 8, 1, '\t', 0) + defer tw.Flush() + for _, inst := range dv { + atbp := "" + if inst.Breakpoint { + atbp = "*" + } + atpc := "" + if inst.AtPC { + atpc = "=>" + } + fmt.Fprintf(tw, "%s\t%s:%d\t%#x%s\t%x\t%s\n", atpc, filepath.Base(inst.Loc.File), inst.Loc.Line, inst.Loc.PC, atbp, inst.Bytes, inst.Text) + } +} diff --git a/vendor/github.com/derekparker/delve/pkg/terminal/docgen.go b/vendor/github.com/derekparker/delve/pkg/terminal/docgen.go new file mode 100644 index 0000000..a9632d9 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/terminal/docgen.go @@ -0,0 +1,54 @@ +package terminal + +import ( + "fmt" + "io" + "strings" +) + +func replaceDocPath(s string) string { + const docpath = "$GOPATH/src/github.com/derekparker/delve/" + + for { + start := strings.Index(s, docpath) + if start < 0 { + return s + } + var end int + for end = start + len(docpath); end < len(s); end++ { + if s[end] == ' ' { + break + } + } + + text := s[start+len(docpath) : end] + s = s[:start] + fmt.Sprintf("[%s](//github.com/derekparker/delve/tree/master/%s)", text, text) + s[end:] + } +} + +func (commands *Commands) WriteMarkdown(w io.Writer) { + fmt.Fprintf(w, "# Commands\n\n") + + fmt.Fprintf(w, "Command | Description\n") + fmt.Fprintf(w, "--------|------------\n") + for _, cmd := range commands.cmds { + h := cmd.helpMsg + if idx := strings.Index(h, "\n"); idx >= 0 { + h = h[:idx] + } + fmt.Fprintf(w, "[%s](#%s) | %s\n", cmd.aliases[0], cmd.aliases[0], h) + } + fmt.Fprintf(w, "\n") + + for _, cmd := range commands.cmds { + fmt.Fprintf(w, "## %s\n%s\n\n", cmd.aliases[0], replaceDocPath(cmd.helpMsg)) + if len(cmd.aliases) > 1 { + fmt.Fprintf(w, "Aliases:") + for _, alias := range cmd.aliases[1:] { + fmt.Fprintf(w, " %s", alias) + } + fmt.Fprintf(w, "\n") + } + fmt.Fprintf(w, "\n") + } +} diff --git a/vendor/github.com/derekparker/delve/pkg/terminal/terminal.go b/vendor/github.com/derekparker/delve/pkg/terminal/terminal.go new file mode 100644 index 0000000..74a7f52 --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/terminal/terminal.go @@ -0,0 +1,251 @@ +package terminal + +import ( + "fmt" + "io" + "os" + "os/signal" + "runtime" + "strings" + + "syscall" + + "github.com/peterh/liner" + + "github.com/derekparker/delve/pkg/config" + "github.com/derekparker/delve/service" +) + +const ( + historyFile string = ".dbg_history" + terminalBlueEscapeCode string = "\033[34m" + terminalResetEscapeCode string = "\033[0m" +) + +// Term represents the terminal running dlv. +type Term struct { + client service.Client + conf *config.Config + prompt string + line *liner.State + cmds *Commands + dumb bool + stdout io.Writer + InitFile string +} + +// New returns a new Term. +func New(client service.Client, conf *config.Config) *Term { + cmds := DebugCommands(client) + if conf != nil && conf.Aliases != nil { + cmds.Merge(conf.Aliases) + } + + var w io.Writer + + dumb := strings.ToLower(os.Getenv("TERM")) == "dumb" + if dumb { + w = os.Stdout + } else { + w = getColorableWriter() + } + + return &Term{ + client: client, + conf: conf, + prompt: "(dlv) ", + line: liner.NewLiner(), + cmds: cmds, + dumb: dumb, + stdout: w, + } +} + +// Close returns the terminal to its previous mode. +func (t *Term) Close() { + t.line.Close() +} + +// Run begins running dlv in the terminal. +func (t *Term) Run() (int, error) { + defer t.Close() + + // Send the debugger a halt command on SIGINT + ch := make(chan os.Signal) + signal.Notify(ch, syscall.SIGINT) + go func() { + for range ch { + fmt.Printf("received SIGINT, stopping process (will not forward signal)") + _, err := t.client.Halt() + if err != nil { + fmt.Fprintf(os.Stderr, "%v", err) + } + } + }() + + t.line.SetCompleter(func(line string) (c []string) { + for _, cmd := range t.cmds.cmds { + for _, alias := range cmd.aliases { + if strings.HasPrefix(alias, strings.ToLower(line)) { + c = append(c, alias) + } + } + } + return + }) + + fullHistoryFile, err := config.GetConfigFilePath(historyFile) + if err != nil { + fmt.Printf("Unable to load history file: %v.", err) + } + + f, err := os.Open(fullHistoryFile) + if err != nil { + f, err = os.Create(fullHistoryFile) + if err != nil { + fmt.Printf("Unable to open history file: %v. History will not be saved for this session.", err) + } + } + + t.line.ReadHistory(f) + f.Close() + fmt.Println("Type 'help' for list of commands.") + + if t.InitFile != "" { + err := t.cmds.executeFile(t, t.InitFile) + if err != nil { + fmt.Fprintf(os.Stderr, "Error executing init file: %s\n", err) + } + } + + for { + cmdstr, err := t.promptForInput() + if err != nil { + if err == io.EOF { + fmt.Println("exit") + return t.handleExit() + } + return 1, fmt.Errorf("Prompt for input failed.\n") + } + + cmdstr, args := parseCommand(cmdstr) + if err := t.cmds.Call(cmdstr, args, t); err != nil { + if _, ok := err.(ExitRequestError); ok { + return t.handleExit() + } + // The type information gets lost in serialization / de-serialization, + // so we do a string compare on the error message to see if the process + // has exited, or if the command actually failed. + if strings.Contains(err.Error(), "exited") { + fmt.Fprintln(os.Stderr, err.Error()) + } else { + fmt.Fprintf(os.Stderr, "Command failed: %s\n", err) + } + } + } +} + +// Println prints a line to the terminal. +func (t *Term) Println(prefix, str string) { + if !t.dumb { + prefix = fmt.Sprintf("%s%s%s", terminalBlueEscapeCode, prefix, terminalResetEscapeCode) + } + fmt.Fprintf(t.stdout, "%s%s\n", prefix, str) +} + +// Substitues directory to source file. +// +// Ensures that only directory is substitued, for example: +// substitute from `/dir/subdir`, substitute to `/new` +// for file path `/dir/subdir/file` will return file path `/new/file`. +// for file path `/dir/subdir-2/file` substitution will not be applied. +// +// If more than one substitution rule is defined, the rules are applied +// in the order they are defined, first rule that matches is used for +// substitution. +func (t *Term) substitutePath(path string) string { + path = crossPlatformPath(path) + if t.conf == nil { + return path + } + separator := string(os.PathSeparator) + for _, r := range t.conf.SubstitutePath { + from := crossPlatformPath(r.From) + to := r.To + + if !strings.HasSuffix(from, separator) { + from = from + separator + } + if !strings.HasSuffix(to, separator) { + to = to + separator + } + if strings.HasPrefix(path, from) { + return strings.Replace(path, from, to, 1) + } + } + return path +} + +func crossPlatformPath(path string) string { + if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { + return strings.ToLower(path) + } + return path +} + +func (t *Term) promptForInput() (string, error) { + l, err := t.line.Prompt(t.prompt) + if err != nil { + return "", err + } + + l = strings.TrimSuffix(l, "\n") + if l != "" { + t.line.AppendHistory(l) + } + + return l, nil +} + +func (t *Term) handleExit() (int, error) { + fullHistoryFile, err := config.GetConfigFilePath(historyFile) + if err != nil { + fmt.Println("Error saving history file:", err) + } else { + if f, err := os.OpenFile(fullHistoryFile, os.O_RDWR, 0666); err == nil { + _, err = t.line.WriteHistory(f) + if err != nil { + fmt.Println("readline history error:", err) + } + f.Close() + } + } + + s, err := t.client.GetState() + if err != nil { + return 1, err + } + if !s.Exited { + kill := true + if t.client.AttachedToExistingProcess() { + answer, err := t.line.Prompt("Would you like to kill the process? [Y/n] ") + if err != nil { + return 2, io.EOF + } + answer = strings.ToLower(strings.TrimSpace(answer)) + kill = (answer != "n" && answer != "no") + } + if err := t.client.Detach(kill); err != nil { + return 1, err + } + } + return 0, nil +} + +func parseCommand(cmdstr string) (string, string) { + vals := strings.SplitN(cmdstr, " ", 2) + if len(vals) == 1 { + return vals[0], "" + } + return vals[0], strings.TrimSpace(vals[1]) +} diff --git a/vendor/github.com/derekparker/delve/pkg/terminal/terminal_other.go b/vendor/github.com/derekparker/delve/pkg/terminal/terminal_other.go new file mode 100644 index 0000000..70a8fee --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/terminal/terminal_other.go @@ -0,0 +1,14 @@ +// +build !windows + +package terminal + +import ( + "io" + "os" +) + +// getColorableWriter simply returns stdout on +// *nix machines. +func getColorableWriter() io.Writer { + return os.Stdout +} diff --git a/vendor/github.com/derekparker/delve/pkg/terminal/terminal_windows.go b/vendor/github.com/derekparker/delve/pkg/terminal/terminal_windows.go new file mode 100644 index 0000000..1d525be --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/terminal/terminal_windows.go @@ -0,0 +1,35 @@ +package terminal + +import ( + "io" + "os" + "strings" + "syscall" + + "github.com/mattn/go-colorable" +) + +// getColorableWriter will return a writer that is capable +// of interpreting ANSI escape codes for terminal colors. +func getColorableWriter() io.Writer { + if strings.ToLower(os.Getenv("ConEmuANSI")) == "on" { + // The ConEmu terminal is installed. Use it. + return os.Stdout + } + + const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + + h, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE) + if err != nil { + return os.Stdout + } + var m uint32 + err = syscall.GetConsoleMode(h, &m) + if err != nil { + return os.Stdout + } + if m&ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 { + return os.Stdout + } + return colorable.NewColorableStdout() +} diff --git a/vendor/github.com/derekparker/delve/pkg/version/version.go b/vendor/github.com/derekparker/delve/pkg/version/version.go new file mode 100644 index 0000000..f89e9df --- /dev/null +++ b/vendor/github.com/derekparker/delve/pkg/version/version.go @@ -0,0 +1,25 @@ +package version + +import "fmt" + +// Version represents the current version of Delve. +type Version struct { + Major string + Minor string + Patch string + Metadata string + Build string +} + +var ( + // DelveVersion is the current version of Delve. + DelveVersion = Version{Major: "0", Minor: "12", Patch: "1", Metadata: ""} +) + +func (v Version) String() string { + ver := fmt.Sprintf("Version: %s.%s.%s", v.Major, v.Minor, v.Patch) + if v.Metadata != "" { + ver += "-" + v.Metadata + } + return fmt.Sprintf("%s\nBuild: %s", ver, v.Build) +} diff --git a/vendor/github.com/derekparker/delve/service/api/conversions.go b/vendor/github.com/derekparker/delve/service/api/conversions.go new file mode 100644 index 0000000..e407d0e --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/api/conversions.go @@ -0,0 +1,276 @@ +package api + +import ( + "bytes" + "debug/gosym" + "go/constant" + "go/printer" + "go/token" + "reflect" + "strconv" + + "github.com/derekparker/delve/pkg/proc" + + "golang.org/x/debug/dwarf" +) + +// ConvertBreakpoint converts from a proc.Breakpoint to +// an api.Breakpoint. +func ConvertBreakpoint(bp *proc.Breakpoint) *Breakpoint { + b := &Breakpoint{ + Name: bp.Name, + ID: bp.ID, + FunctionName: bp.FunctionName, + File: bp.File, + Line: bp.Line, + Addr: bp.Addr, + Tracepoint: bp.Tracepoint, + Stacktrace: bp.Stacktrace, + Goroutine: bp.Goroutine, + Variables: bp.Variables, + LoadArgs: LoadConfigFromProc(bp.LoadArgs), + LoadLocals: LoadConfigFromProc(bp.LoadLocals), + TotalHitCount: bp.TotalHitCount, + } + + b.HitCount = map[string]uint64{} + for idx := range bp.HitCount { + b.HitCount[strconv.Itoa(idx)] = bp.HitCount[idx] + } + + var buf bytes.Buffer + printer.Fprint(&buf, token.NewFileSet(), bp.Cond) + b.Cond = buf.String() + + return b +} + +// ConvertThread converts a proc.Thread into an +// api thread. +func ConvertThread(th *proc.Thread) *Thread { + var ( + function *Function + file string + line int + pc uint64 + gid int + ) + + loc, err := th.Location() + if err == nil { + pc = loc.PC + file = loc.File + line = loc.Line + function = ConvertFunction(loc.Fn) + } + + var bp *Breakpoint + + if th.CurrentBreakpoint != nil && th.BreakpointConditionMet { + bp = ConvertBreakpoint(th.CurrentBreakpoint) + } + + if g, _ := th.GetG(); g != nil { + gid = g.ID + } + + return &Thread{ + ID: th.ID, + PC: pc, + File: file, + Line: line, + Function: function, + GoroutineID: gid, + Breakpoint: bp, + } +} + +func prettyTypeName(typ dwarf.Type) string { + if typ == nil { + return "" + } + if typ.Common().Name != "" { + return typ.Common().Name + } + r := typ.String() + if r == "*void" { + return "unsafe.Pointer" + } + return r +} + +func convertFloatValue(v *proc.Variable, sz int) string { + switch v.FloatSpecial { + case proc.FloatIsPosInf: + return "+Inf" + case proc.FloatIsNegInf: + return "-Inf" + case proc.FloatIsNaN: + return "NaN" + } + f, _ := constant.Float64Val(v.Value) + return strconv.FormatFloat(f, 'f', -1, sz) +} + +// ConvertVar converts from proc.Variable to api.Variable. +func ConvertVar(v *proc.Variable) *Variable { + r := Variable{ + Addr: v.Addr, + OnlyAddr: v.OnlyAddr, + Name: v.Name, + Kind: v.Kind, + Len: v.Len, + Cap: v.Cap, + } + + r.Type = prettyTypeName(v.DwarfType) + r.RealType = prettyTypeName(v.RealType) + + if v.Unreadable != nil { + r.Unreadable = v.Unreadable.Error() + } + + if v.Value != nil { + switch v.Kind { + case reflect.Float32: + r.Value = convertFloatValue(v, 32) + case reflect.Float64: + r.Value = convertFloatValue(v, 64) + case reflect.String, reflect.Func: + r.Value = constant.StringVal(v.Value) + default: + r.Value = v.Value.String() + } + } + + switch v.Kind { + case reflect.Complex64: + r.Children = make([]Variable, 2) + r.Len = 2 + + real, _ := constant.Float64Val(constant.Real(v.Value)) + imag, _ := constant.Float64Val(constant.Imag(v.Value)) + + r.Children[0].Name = "real" + r.Children[0].Kind = reflect.Float32 + r.Children[0].Value = strconv.FormatFloat(real, 'f', -1, 32) + + r.Children[1].Name = "imaginary" + r.Children[1].Kind = reflect.Float32 + r.Children[1].Value = strconv.FormatFloat(imag, 'f', -1, 32) + case reflect.Complex128: + r.Children = make([]Variable, 2) + r.Len = 2 + + real, _ := constant.Float64Val(constant.Real(v.Value)) + imag, _ := constant.Float64Val(constant.Imag(v.Value)) + + r.Children[0].Name = "real" + r.Children[0].Kind = reflect.Float64 + r.Children[0].Value = strconv.FormatFloat(real, 'f', -1, 64) + + r.Children[1].Name = "imaginary" + r.Children[1].Kind = reflect.Float64 + r.Children[1].Value = strconv.FormatFloat(imag, 'f', -1, 64) + + default: + r.Children = make([]Variable, len(v.Children)) + + for i := range v.Children { + r.Children[i] = *ConvertVar(&v.Children[i]) + } + } + + return &r +} + +// ConvertFunction converts from gosym.Func to +// api.Function. +func ConvertFunction(fn *gosym.Func) *Function { + if fn == nil { + return nil + } + + return &Function{ + Name: fn.Name, + Type: fn.Type, + Value: fn.Value, + GoType: fn.GoType, + } +} + +// ConvertGoroutine converts from proc.G to api.Goroutine. +func ConvertGoroutine(g *proc.G) *Goroutine { + th := g.Thread() + tid := 0 + if th != nil { + tid = th.ID + } + return &Goroutine{ + ID: g.ID, + CurrentLoc: ConvertLocation(g.CurrentLoc), + UserCurrentLoc: ConvertLocation(g.UserCurrent()), + GoStatementLoc: ConvertLocation(g.Go()), + ThreadID: tid, + } +} + +// ConvertLocation converts from proc.Location to api.Location. +func ConvertLocation(loc proc.Location) Location { + return Location{ + PC: loc.PC, + File: loc.File, + Line: loc.Line, + Function: ConvertFunction(loc.Fn), + } +} + +func ConvertAsmInstruction(inst proc.AsmInstruction, text string) AsmInstruction { + var destloc *Location + if inst.DestLoc != nil { + r := ConvertLocation(*inst.DestLoc) + destloc = &r + } + return AsmInstruction{ + Loc: ConvertLocation(inst.Loc), + DestLoc: destloc, + Text: text, + Bytes: inst.Bytes, + Breakpoint: inst.Breakpoint, + AtPC: inst.AtPC, + } +} + +func LoadConfigToProc(cfg *LoadConfig) *proc.LoadConfig { + if cfg == nil { + return nil + } + return &proc.LoadConfig{ + cfg.FollowPointers, + cfg.MaxVariableRecurse, + cfg.MaxStringLen, + cfg.MaxArrayValues, + cfg.MaxStructFields, + } +} + +func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig { + if cfg == nil { + return nil + } + return &LoadConfig{ + cfg.FollowPointers, + cfg.MaxVariableRecurse, + cfg.MaxStringLen, + cfg.MaxArrayValues, + cfg.MaxStructFields, + } +} + +func ConvertRegisters(in []proc.Register) (out []Register) { + out = make([]Register, len(in)) + for i := range in { + out[i] = Register{in[i].Name, in[i].Value} + } + return +} diff --git a/vendor/github.com/derekparker/delve/service/api/prettyprint.go b/vendor/github.com/derekparker/delve/service/api/prettyprint.go new file mode 100644 index 0000000..7c53c1b --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/api/prettyprint.go @@ -0,0 +1,323 @@ +package api + +import ( + "bytes" + "fmt" + "io" + "reflect" +) + +const ( + // strings longer than this will cause slices, arrays and structs to be printed on multiple lines when newlines is enabled + maxShortStringLen = 7 + // string used for one indentation level (when printing on multiple lines) + indentString = "\t" +) + +// SinglelineString returns a representation of v on a single line. +func (v *Variable) SinglelineString() string { + var buf bytes.Buffer + v.writeTo(&buf, true, false, true, "") + return buf.String() +} + +// MultilineString returns a representation of v on multiple lines. +func (v *Variable) MultilineString(indent string) string { + var buf bytes.Buffer + v.writeTo(&buf, true, true, true, indent) + return buf.String() +} + +func (v *Variable) writeTo(buf io.Writer, top, newlines, includeType bool, indent string) { + if v.Unreadable != "" { + fmt.Fprintf(buf, "(unreadable %s)", v.Unreadable) + return + } + + if !top && v.Addr == 0 { + if includeType && v.Type != "void" { + fmt.Fprintf(buf, "%s nil", v.Type) + } else { + fmt.Fprintf(buf, "nil") + } + return + } + + switch v.Kind { + case reflect.Slice: + v.writeSliceTo(buf, newlines, includeType, indent) + case reflect.Array: + v.writeArrayTo(buf, newlines, includeType, indent) + case reflect.Ptr: + if v.Type == "" { + fmt.Fprintf(buf, "nil") + } else if v.Children[0].OnlyAddr && v.Children[0].Addr != 0 { + fmt.Fprintf(buf, "(%s)(0x%x)", v.Type, v.Children[0].Addr) + } else { + fmt.Fprintf(buf, "*") + v.Children[0].writeTo(buf, false, newlines, includeType, indent) + } + case reflect.UnsafePointer: + fmt.Fprintf(buf, "unsafe.Pointer(0x%x)", v.Children[0].Addr) + case reflect.String: + v.writeStringTo(buf) + case reflect.Chan: + if newlines { + v.writeStructTo(buf, newlines, includeType, indent) + } else { + if len(v.Children) == 0 { + fmt.Fprintf(buf, "%s nil", v.Type) + } else { + fmt.Fprintf(buf, "%s %s/%s", v.Type, v.Children[0].Value, v.Children[1].Value) + } + } + case reflect.Struct: + v.writeStructTo(buf, newlines, includeType, indent) + case reflect.Interface: + if includeType { + if v.Children[0].Kind == reflect.Invalid { + fmt.Fprintf(buf, "%s ", v.Type) + if v.Children[0].Addr == 0 { + fmt.Fprintf(buf, "nil") + return + } + } else { + fmt.Fprintf(buf, "%s(%s) ", v.Type, v.Children[0].Type) + } + } + data := v.Children[0] + if data.Kind == reflect.Ptr { + if len(data.Children) == 0 { + fmt.Fprintf(buf, "...") + } else if data.Children[0].Addr == 0 { + fmt.Fprintf(buf, "nil") + } else if data.Children[0].OnlyAddr { + fmt.Fprintf(buf, "0x%x", v.Children[0].Addr) + } else { + v.Children[0].writeTo(buf, false, newlines, !includeType, indent) + } + } else { + v.Children[0].writeTo(buf, false, newlines, !includeType, indent) + } + case reflect.Map: + v.writeMapTo(buf, newlines, includeType, indent) + case reflect.Func: + if v.Value == "" { + fmt.Fprintf(buf, "nil") + } else { + fmt.Fprintf(buf, "%s", v.Value) + } + case reflect.Complex64, reflect.Complex128: + fmt.Fprintf(buf, "(%s + %si)", v.Children[0].Value, v.Children[1].Value) + default: + if v.Value != "" { + buf.Write([]byte(v.Value)) + } else { + fmt.Fprintf(buf, "(unknown %s)", v.Kind) + } + } +} + +func (v *Variable) writeStringTo(buf io.Writer) { + s := v.Value + if len(s) != int(v.Len) { + s = fmt.Sprintf("%s...+%d more", s, int(v.Len)-len(s)) + } + fmt.Fprintf(buf, "%q", s) +} + +func (v *Variable) writeSliceTo(buf io.Writer, newlines, includeType bool, indent string) { + if includeType { + fmt.Fprintf(buf, "%s len: %d, cap: %d, ", v.Type, v.Len, v.Cap) + } + v.writeSliceOrArrayTo(buf, newlines, indent) +} + +func (v *Variable) writeArrayTo(buf io.Writer, newlines, includeType bool, indent string) { + if includeType { + fmt.Fprintf(buf, "%s ", v.Type) + } + v.writeSliceOrArrayTo(buf, newlines, indent) +} + +func (v *Variable) writeStructTo(buf io.Writer, newlines, includeType bool, indent string) { + if int(v.Len) != len(v.Children) && len(v.Children) == 0 { + fmt.Fprintf(buf, "(*%s)(0x%x)", v.Type, v.Addr) + return + } + + if includeType { + fmt.Fprintf(buf, "%s ", v.Type) + } + + nl := v.shouldNewlineStruct(newlines) + + fmt.Fprintf(buf, "{") + + for i := range v.Children { + if nl { + fmt.Fprintf(buf, "\n%s%s", indent, indentString) + } + fmt.Fprintf(buf, "%s: ", v.Children[i].Name) + v.Children[i].writeTo(buf, false, nl, true, indent+indentString) + if i != len(v.Children)-1 || nl { + fmt.Fprintf(buf, ",") + if !nl { + fmt.Fprintf(buf, " ") + } + } + } + + if len(v.Children) != int(v.Len) { + if nl { + fmt.Fprintf(buf, "\n%s%s", indent, indentString) + } else { + fmt.Fprintf(buf, ",") + } + fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children)) + } + + fmt.Fprintf(buf, "}") +} + +func (v *Variable) writeMapTo(buf io.Writer, newlines, includeType bool, indent string) { + if includeType { + fmt.Fprintf(buf, "%s ", v.Type) + } + + nl := newlines && (len(v.Children) > 0) + + fmt.Fprintf(buf, "[") + + for i := 0; i < len(v.Children); i += 2 { + key := &v.Children[i] + value := &v.Children[i+1] + + if nl { + fmt.Fprintf(buf, "\n%s%s", indent, indentString) + } + + key.writeTo(buf, false, false, false, indent+indentString) + fmt.Fprintf(buf, ": ") + value.writeTo(buf, false, nl, false, indent+indentString) + if i != len(v.Children)-1 || nl { + fmt.Fprintf(buf, ", ") + } + } + + if len(v.Children)/2 != int(v.Len) { + if len(v.Children) != 0 { + if nl { + fmt.Fprintf(buf, "\n%s%s", indent, indentString) + } else { + fmt.Fprintf(buf, ",") + } + fmt.Fprintf(buf, "...+%d more", int(v.Len)-(len(v.Children)/2)) + } else { + fmt.Fprintf(buf, "...") + } + } + + if nl { + fmt.Fprintf(buf, "\n%s", indent) + } + fmt.Fprintf(buf, "]") +} + +func (v *Variable) shouldNewlineArray(newlines bool) bool { + if !newlines || len(v.Children) == 0 { + return false + } + + kind, hasptr := (&v.Children[0]).recursiveKind() + + switch kind { + case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface: + return true + case reflect.String: + if hasptr { + return true + } + for i := range v.Children { + if len(v.Children[i].Value) > maxShortStringLen { + return true + } + } + return false + default: + return false + } +} + +func (v *Variable) recursiveKind() (reflect.Kind, bool) { + hasptr := false + var kind reflect.Kind + for { + kind = v.Kind + if kind == reflect.Ptr { + hasptr = true + v = &(v.Children[0]) + } else { + break + } + } + return kind, hasptr +} + +func (v *Variable) shouldNewlineStruct(newlines bool) bool { + if !newlines || len(v.Children) == 0 { + return false + } + + for i := range v.Children { + kind, hasptr := (&v.Children[i]).recursiveKind() + + switch kind { + case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface: + return true + case reflect.String: + if hasptr { + return true + } + if len(v.Children[i].Value) > maxShortStringLen { + return true + } + } + } + + return false +} + +func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent string) { + nl := v.shouldNewlineArray(newlines) + fmt.Fprintf(buf, "[") + + for i := range v.Children { + if nl { + fmt.Fprintf(buf, "\n%s%s", indent, indentString) + } + v.Children[i].writeTo(buf, false, nl, false, indent+indentString) + if i != len(v.Children)-1 || nl { + fmt.Fprintf(buf, ",") + } + } + + if len(v.Children) != int(v.Len) { + if len(v.Children) != 0 { + if nl { + fmt.Fprintf(buf, "\n%s%s", indent, indentString) + } else { + fmt.Fprintf(buf, ",") + } + fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children)) + } else { + fmt.Fprintf(buf, "...") + } + } + + if nl { + fmt.Fprintf(buf, "\n%s", indent) + } + + fmt.Fprintf(buf, "]") +} diff --git a/vendor/github.com/derekparker/delve/service/api/types.go b/vendor/github.com/derekparker/delve/service/api/types.go new file mode 100644 index 0000000..677a8d3 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/api/types.go @@ -0,0 +1,320 @@ +package api + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "strconv" + "unicode" + + "github.com/derekparker/delve/pkg/proc" +) + +var NotExecutableErr = proc.NotExecutableErr + +// DebuggerState represents the current context of the debugger. +type DebuggerState struct { + // CurrentThread is the currently selected debugger thread. + CurrentThread *Thread `json:"currentThread,omitempty"` + // SelectedGoroutine is the currently selected goroutine + SelectedGoroutine *Goroutine `json:"currentGoroutine,omitempty"` + // List of all the process threads + Threads []*Thread + // NextInProgress indicates that a next or step operation was interrupted by another breakpoint + // or a manual stop and is waiting to complete. + // While NextInProgress is set further requests for next or step may be rejected. + // Either execute continue until NextInProgress is false or call CancelNext + NextInProgress bool + // Exited indicates whether the debugged process has exited. + Exited bool `json:"exited"` + ExitStatus int `json:"exitStatus"` + // Filled by RPCClient.Continue, indicates an error + Err error `json:"-"` +} + +// Breakpoint addresses a location at which process execution may be +// suspended. +type Breakpoint struct { + // ID is a unique identifier for the breakpoint. + ID int `json:"id"` + // User defined name of the breakpoint + Name string `json:"name"` + // Addr is the address of the breakpoint. + Addr uint64 `json:"addr"` + // File is the source file for the breakpoint. + File string `json:"file"` + // Line is a line in File for the breakpoint. + Line int `json:"line"` + // FunctionName is the name of the function at the current breakpoint, and + // may not always be available. + FunctionName string `json:"functionName,omitempty"` + + // Breakpoint condition + Cond string + + // tracepoint flag + Tracepoint bool `json:"continue"` + // retrieve goroutine information + Goroutine bool `json:"goroutine"` + // number of stack frames to retrieve + Stacktrace int `json:"stacktrace"` + // expressions to evaluate + Variables []string `json:"variables,omitempty"` + // LoadArgs requests loading function arguments when the breakpoint is hit + LoadArgs *LoadConfig + // LoadLocals requests loading function locals when the breakpoint is hit + LoadLocals *LoadConfig + // number of times a breakpoint has been reached in a certain goroutine + HitCount map[string]uint64 `json:"hitCount"` + // number of times a breakpoint has been reached + TotalHitCount uint64 `json:"totalHitCount"` +} + +func ValidBreakpointName(name string) error { + if _, err := strconv.Atoi(name); err == nil { + return errors.New("breakpoint name can not be a number") + } + + for _, ch := range name { + if !(unicode.IsLetter(ch) || unicode.IsDigit(ch)) { + return fmt.Errorf("invalid character in breakpoint name '%c'", ch) + } + } + + return nil +} + +// Thread is a thread within the debugged process. +type Thread struct { + // ID is a unique identifier for the thread. + ID int `json:"id"` + // PC is the current program counter for the thread. + PC uint64 `json:"pc"` + // File is the file for the program counter. + File string `json:"file"` + // Line is the line number for the program counter. + Line int `json:"line"` + // Function is function information at the program counter. May be nil. + Function *Function `json:"function,omitempty"` + + // ID of the goroutine running on this thread + GoroutineID int `json:"goroutineID"` + + // Breakpoint this thread is stopped at + Breakpoint *Breakpoint `json:"breakPoint,omitempty"` + // Informations requested by the current breakpoint + BreakpointInfo *BreakpointInfo `json:"breakPointInfo,omitrempty"` +} + +type Location struct { + PC uint64 `json:"pc"` + File string `json:"file"` + Line int `json:"line"` + Function *Function `json:"function,omitempty"` +} + +type Stackframe struct { + Location + Locals []Variable + Arguments []Variable +} + +func (frame *Stackframe) Var(name string) *Variable { + for i := range frame.Locals { + if frame.Locals[i].Name == name { + return &frame.Locals[i] + } + } + for i := range frame.Arguments { + if frame.Arguments[i].Name == name { + return &frame.Arguments[i] + } + } + return nil +} + +// Function represents thread-scoped function information. +type Function struct { + // Name is the function name. + Name string `json:"name"` + Value uint64 `json:"value"` + Type byte `json:"type"` + GoType uint64 `json:"goType"` +} + +// Variable describes a variable. +type Variable struct { + // Name of the variable or struct member + Name string `json:"name"` + // Address of the variable or struct member + Addr uintptr `json:"addr"` + // Only the address field is filled (result of evaluating expressions like &) + OnlyAddr bool `json:"onlyAddr"` + // Go type of the variable + Type string `json:"type"` + // Type of the variable after resolving any typedefs + RealType string `json:"realType"` + + Kind reflect.Kind `json:"kind"` + + //Strings have their length capped at proc.maxArrayValues, use Len for the real length of a string + //Function variables will store the name of the function in this field + Value string `json:"value"` + + // Number of elements in an array or a slice, number of keys for a map, number of struct members for a struct, length of strings + Len int64 `json:"len"` + // Cap value for slices + Cap int64 `json:"cap"` + + // Array and slice elements, member fields of structs, key/value pairs of maps, value of complex numbers + // The Name field in this slice will always be the empty string except for structs (when it will be the field name) and for complex numbers (when it will be "real" and "imaginary") + // For maps each map entry will have to items in this slice, even numbered items will represent map keys and odd numbered items will represent their values + // This field's length is capped at proc.maxArrayValues for slices and arrays and 2*proc.maxArrayValues for maps, in the circumnstances where the cap takes effect len(Children) != Len + // The other length cap applied to this field is related to maximum recursion depth, when the maximum recursion depth is reached this field is left empty, contrary to the previous one this cap also applies to structs (otherwise structs will always have all their member fields returned) + Children []Variable `json:"children"` + + // Unreadable addresses will have this field set + Unreadable string `json:"unreadable"` +} + +// LoadConfig describes how to load values from target's memory +type LoadConfig struct { + // FollowPointers requests pointers to be automatically dereferenced. + FollowPointers bool + // MaxVariableRecurse is how far to recurse when evaluating nested types. + MaxVariableRecurse int + // MaxStringLen is the maximum number of bytes read from a string + MaxStringLen int + // MaxArrayValues is the maximum number of elements read from an array, a slice or a map. + MaxArrayValues int + // MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields. + MaxStructFields int +} + +// Goroutine represents the information relevant to Delve from the runtime's +// internal G structure. +type Goroutine struct { + // ID is a unique identifier for the goroutine. + ID int `json:"id"` + // Current location of the goroutine + CurrentLoc Location `json:"currentLoc"` + // Current location of the goroutine, excluding calls inside runtime + UserCurrentLoc Location `json:"userCurrentLoc"` + // Location of the go instruction that started this goroutine + GoStatementLoc Location `json:"goStatementLoc"` + // ID of the associated thread for running goroutines + ThreadID int `json:"threadID"` +} + +// DebuggerCommand is a command which changes the debugger's execution state. +type DebuggerCommand struct { + // Name is the command to run. + Name string `json:"name"` + // ThreadID is used to specify which thread to use with the SwitchThread + // command. + ThreadID int `json:"threadID,omitempty"` + // GoroutineID is used to specify which thread to use with the SwitchGoroutine + // command. + GoroutineID int `json:"goroutineID,omitempty"` +} + +// Informations about the current breakpoint +type BreakpointInfo struct { + Stacktrace []Stackframe `json:"stacktrace,omitempty"` + Goroutine *Goroutine `json:"goroutine,omitempty"` + Variables []Variable `json:"variables,omitempty"` + Arguments []Variable `json:"arguments,omitempty"` + Locals []Variable `json:"locals,omitempty"` +} + +type EvalScope struct { + GoroutineID int + Frame int +} + +const ( + // Continue resumes process execution. + Continue = "continue" + // Step continues to next source line, entering function calls. + Step = "step" + // StepOut continues to the return address of the current function + StepOut = "stepOut" + // SingleStep continues for exactly 1 cpu instruction. + StepInstruction = "stepInstruction" + // Next continues to the next source line, not entering function calls. + Next = "next" + // SwitchThread switches the debugger's current thread context. + SwitchThread = "switchThread" + // SwitchGoroutine switches the debugger's current thread context to the thread running the specified goroutine + SwitchGoroutine = "switchGoroutine" + // Halt suspends the process. + Halt = "halt" +) + +type AssemblyFlavour int + +const ( + GNUFlavour = AssemblyFlavour(proc.GNUFlavour) + IntelFlavour = AssemblyFlavour(proc.IntelFlavour) +) + +// AsmInstruction represents one assembly instruction at some address +type AsmInstruction struct { + // Loc is the location of this instruction + Loc Location + // Destination of CALL instructions + DestLoc *Location + // Text is the formatted representation of the instruction + Text string + // Bytes is the instruction as read from memory + Bytes []byte + // If Breakpoint is true a breakpoint is set at this instruction + Breakpoint bool + // In AtPC is true this is the instruction the current thread is stopped at + AtPC bool +} + +type AsmInstructions []AsmInstruction + +type GetVersionIn struct { +} + +type GetVersionOut struct { + DelveVersion string + APIVersion int +} + +type SetAPIVersionIn struct { + APIVersion int +} + +type SetAPIVersionOut struct { +} + +type Register struct { + Name string + Value string +} + +type Registers []Register + +func (regs Registers) String() string { + maxlen := 0 + for _, reg := range regs { + if n := len(reg.Name); n > maxlen { + maxlen = n + } + } + + var buf bytes.Buffer + for _, reg := range regs { + fmt.Fprintf(&buf, "%*s = %s\n", maxlen, reg.Name, reg.Value) + } + return buf.String() +} + +type DiscardedBreakpoint struct { + Breakpoint *Breakpoint + Reason string +} diff --git a/vendor/github.com/derekparker/delve/service/client.go b/vendor/github.com/derekparker/delve/service/client.go new file mode 100644 index 0000000..fe06a94 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/client.go @@ -0,0 +1,115 @@ +package service + +import ( + "time" + + "github.com/derekparker/delve/service/api" +) + +// Client represents a debugger service client. All client methods are +// synchronous. +type Client interface { + // Returns the pid of the process we are debugging. + ProcessPid() int + + // LastModified returns the time that the process' executable was modified. + LastModified() time.Time + + // Detach detaches the debugger, optionally killing the process. + Detach(killProcess bool) error + + // Restarts program. + Restart() ([]api.DiscardedBreakpoint, error) + + // GetState returns the current debugger state. + GetState() (*api.DebuggerState, error) + + // Continue resumes process execution. + Continue() <-chan *api.DebuggerState + // Next continues to the next source line, not entering function calls. + Next() (*api.DebuggerState, error) + // Step continues to the next source line, entering function calls. + Step() (*api.DebuggerState, error) + // StepOut continues to the return address of the current function + StepOut() (*api.DebuggerState, error) + + // SingleStep will step a single cpu instruction. + StepInstruction() (*api.DebuggerState, error) + // SwitchThread switches the current thread context. + SwitchThread(threadID int) (*api.DebuggerState, error) + // SwitchGoroutine switches the current goroutine (and the current thread as well) + SwitchGoroutine(goroutineID int) (*api.DebuggerState, error) + // Halt suspends the process. + Halt() (*api.DebuggerState, error) + + // GetBreakpoint gets a breakpoint by ID. + GetBreakpoint(id int) (*api.Breakpoint, error) + // GetBreakpointByName gets a breakpoint by name. + GetBreakpointByName(name string) (*api.Breakpoint, error) + // CreateBreakpoint creates a new breakpoint. + CreateBreakpoint(*api.Breakpoint) (*api.Breakpoint, error) + // ListBreakpoints gets all breakpoints. + ListBreakpoints() ([]*api.Breakpoint, error) + // ClearBreakpoint deletes a breakpoint by ID. + ClearBreakpoint(id int) (*api.Breakpoint, error) + // ClearBreakpointByName deletes a breakpoint by name + ClearBreakpointByName(name string) (*api.Breakpoint, error) + // Allows user to update an existing breakpoint for example to change the information + // retrieved when the breakpoint is hit or to change, add or remove the break condition + AmendBreakpoint(*api.Breakpoint) error + // Cancels a Next or Step call that was interrupted by a manual stop or by another breakpoint + CancelNext() error + + // ListThreads lists all threads. + ListThreads() ([]*api.Thread, error) + // GetThread gets a thread by its ID. + GetThread(id int) (*api.Thread, error) + + // ListPackageVariables lists all package variables in the context of the current thread. + ListPackageVariables(filter string, cfg api.LoadConfig) ([]api.Variable, error) + // EvalVariable returns a variable in the context of the current thread. + EvalVariable(scope api.EvalScope, symbol string, cfg api.LoadConfig) (*api.Variable, error) + + // SetVariable sets the value of a variable + SetVariable(scope api.EvalScope, symbol, value string) error + + // ListSources lists all source files in the process matching filter. + ListSources(filter string) ([]string, error) + // ListFunctions lists all functions in the process matching filter. + ListFunctions(filter string) ([]string, error) + // ListTypes lists all types in the process matching filter. + ListTypes(filter string) ([]string, error) + // ListLocals lists all local variables in scope. + ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) + // ListFunctionArgs lists all arguments to the current function. + ListFunctionArgs(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) + // ListRegisters lists registers and their values. + ListRegisters(threadID int, includeFp bool) (api.Registers, error) + + // ListGoroutines lists all goroutines. + ListGoroutines() ([]*api.Goroutine, error) + + // Returns stacktrace + Stacktrace(int, int, *api.LoadConfig) ([]api.Stackframe, error) + + // Returns whether we attached to a running process or not + AttachedToExistingProcess() bool + + // Returns concrete location information described by a location expression + // loc ::= : | [:] | // | (+|-) | | *
+ // * can be the full path of a file or just a suffix + // * ::= .. | .(*). | . | . | (*). | + // * must be unambiguous + // * // will return a location for each function matched by regex + // * + returns a location for the line that is lines after the current line + // * - returns a location for the line that is lines before the current line + // * returns a location for a line in the current file + // * *
returns the location corresponding to the specified address + // NOTE: this function does not actually set breakpoints. + FindLocation(scope api.EvalScope, loc string) ([]api.Location, error) + + // Disassemble code between startPC and endPC + DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) + // Disassemble code of the function containing PC + DisassemblePC(scope api.EvalScope, pc uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) +} diff --git a/vendor/github.com/derekparker/delve/service/config.go b/vendor/github.com/derekparker/delve/service/config.go new file mode 100644 index 0000000..dd2991c --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/config.go @@ -0,0 +1,28 @@ +package service + +import "net" + +// Config provides the configuration to start a Debugger and expose it with a +// service. +// +// Only one of ProcessArgs or AttachPid should be specified. If ProcessArgs is +// provided, a new process will be launched. Otherwise, the debugger will try +// to attach to an existing process with AttachPid. +type Config struct { + // Listener is used to serve requests. + Listener net.Listener + // ProcessArgs are the arguments to launch a new process. + ProcessArgs []string + // WorkingDir is working directory of the new process. This field is used + // only when launching a new process. + WorkingDir string + + // AttachPid is the PID of an existing process to which the debugger should + // attach. + AttachPid int + // AcceptMulti configures the server to accept multiple connection. + // Note that the server API is not reentrant and clients will have to coordinate. + AcceptMulti bool + // APIVersion selects which version of the API to serve (default: 1). + APIVersion int +} diff --git a/vendor/github.com/derekparker/delve/service/debugger/debugger.go b/vendor/github.com/derekparker/delve/service/debugger/debugger.go new file mode 100644 index 0000000..705a2f1 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/debugger/debugger.go @@ -0,0 +1,835 @@ +package debugger + +import ( + "debug/gosym" + "errors" + "fmt" + "go/parser" + "log" + "path/filepath" + "regexp" + "runtime" + "strings" + "sync" + "time" + + "github.com/derekparker/delve/pkg/proc" + "github.com/derekparker/delve/pkg/target" + "github.com/derekparker/delve/service/api" +) + +// Debugger service. +// +// Debugger provides a higher level of +// abstraction over proc.Process. +// It handles converting from internal types to +// the types expected by clients. It also handles +// functionality needed by clients, but not needed in +// lower lever packages such as proc. +type Debugger struct { + config *Config + // TODO(DO NOT MERGE WITHOUT) rename to targetMutex + processMutex sync.Mutex + target target.Interface +} + +// Config provides the configuration to start a Debugger. +// +// Only one of ProcessArgs or AttachPid should be specified. If ProcessArgs is +// provided, a new process will be launched. Otherwise, the debugger will try +// to attach to an existing process with AttachPid. +type Config struct { + // ProcessArgs are the arguments to launch a new process. + ProcessArgs []string + // WorkingDir is working directory of the new process. This field is used + // only when launching a new process. + WorkingDir string + + // AttachPid is the PID of an existing process to which the debugger should + // attach. + AttachPid int +} + +// New creates a new Debugger. +func New(config *Config) (*Debugger, error) { + d := &Debugger{ + config: config, + } + + // Create the process by either attaching or launching. + if d.config.AttachPid > 0 { + log.Printf("attaching to pid %d", d.config.AttachPid) + p, err := proc.Attach(d.config.AttachPid) + if err != nil { + return nil, attachErrorMessage(d.config.AttachPid, err) + } + d.target = p + } else { + log.Printf("launching process with args: %v", d.config.ProcessArgs) + p, err := proc.Launch(d.config.ProcessArgs, d.config.WorkingDir) + if err != nil { + if err != proc.NotExecutableErr && err != proc.UnsupportedArchErr { + err = fmt.Errorf("could not launch process: %s", err) + } + return nil, err + } + d.target = p + } + return d, nil +} + +// ProcessPid returns the PID of the process +// the debugger is debugging. +func (d *Debugger) ProcessPid() int { + return d.target.Pid() +} + +// LastModified returns the time that the process' executable was last +// modified. +func (d *Debugger) LastModified() time.Time { + return d.target.LastModified() +} + +// Detach detaches from the target process. +// If `kill` is true we will kill the process after +// detaching. +func (d *Debugger) Detach(kill bool) error { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + return d.detach(kill) +} + +func (d *Debugger) detach(kill bool) error { + if d.config.AttachPid != 0 { + return d.target.Detach(kill) + } + return d.target.Kill() +} + +// Restart will restart the target process, first killing +// and then exec'ing it again. +func (d *Debugger) Restart() ([]api.DiscardedBreakpoint, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + if !d.target.Exited() { + if d.target.Running() { + d.target.Halt() + } + // Ensure the process is in a PTRACE_STOP. + if err := stopProcess(d.ProcessPid()); err != nil { + return nil, err + } + if err := d.detach(true); err != nil { + return nil, err + } + } + p, err := proc.Launch(d.config.ProcessArgs, d.config.WorkingDir) + if err != nil { + return nil, fmt.Errorf("could not launch process: %s", err) + } + discarded := []api.DiscardedBreakpoint{} + for _, oldBp := range d.breakpoints() { + if oldBp.ID < 0 { + continue + } + if len(oldBp.File) > 0 { + oldBp.Addr, err = p.FindFileLocation(oldBp.File, oldBp.Line) + if err != nil { + discarded = append(discarded, api.DiscardedBreakpoint{oldBp, err.Error()}) + continue + } + } + newBp, err := p.SetBreakpoint(oldBp.Addr, proc.UserBreakpoint, nil) + if err != nil { + return nil, err + } + if err := copyBreakpointInfo(newBp, oldBp); err != nil { + return nil, err + } + } + d.target = p + return discarded, nil +} + +// State returns the current state of the debugger. +func (d *Debugger) State() (*api.DebuggerState, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + return d.state() +} + +func (d *Debugger) state() (*api.DebuggerState, error) { + if d.target.Exited() { + return nil, proc.ProcessExitedError{Pid: d.ProcessPid()} + } + + var ( + state *api.DebuggerState + goroutine *api.Goroutine + ) + + if d.target.SelectedGoroutine() != nil { + goroutine = api.ConvertGoroutine(d.target.SelectedGoroutine()) + } + + state = &api.DebuggerState{ + SelectedGoroutine: goroutine, + Exited: d.target.Exited(), + } + + for i := range d.target.Threads() { + th := api.ConvertThread(d.target.Threads()[i]) + state.Threads = append(state.Threads, th) + if i == d.target.CurrentThread().ID { + state.CurrentThread = th + } + } + + for _, bp := range d.target.Breakpoints() { + if bp.Internal() { + state.NextInProgress = true + break + } + } + + return state, nil +} + +// CreateBreakpoint creates a breakpoint. +func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + var ( + createdBp *api.Breakpoint + addr uint64 + err error + ) + + if requestedBp.Name != "" { + if err = api.ValidBreakpointName(requestedBp.Name); err != nil { + return nil, err + } + if d.findBreakpointByName(requestedBp.Name) != nil { + return nil, errors.New("breakpoint name already exists") + } + } + + switch { + case len(requestedBp.File) > 0: + fileName := requestedBp.File + if runtime.GOOS == "windows" { + // Accept fileName which is case-insensitive and slash-insensitive match + fileNameNormalized := strings.ToLower(filepath.ToSlash(fileName)) + for symFile := range d.target.Sources() { + if fileNameNormalized == strings.ToLower(filepath.ToSlash(symFile)) { + fileName = symFile + break + } + } + } + addr, err = d.target.FindFileLocation(fileName, requestedBp.Line) + case len(requestedBp.FunctionName) > 0: + if requestedBp.Line >= 0 { + addr, err = d.target.FindFunctionLocation(requestedBp.FunctionName, false, requestedBp.Line) + } else { + addr, err = d.target.FindFunctionLocation(requestedBp.FunctionName, true, 0) + } + default: + addr = requestedBp.Addr + } + + if err != nil { + return nil, err + } + + bp, err := d.target.SetBreakpoint(addr, proc.UserBreakpoint, nil) + if err != nil { + return nil, err + } + if err := copyBreakpointInfo(bp, requestedBp); err != nil { + if _, err1 := d.target.ClearBreakpoint(bp.Addr); err1 != nil { + err = fmt.Errorf("error while creating breakpoint: %v, additionally the breakpoint could not be properly rolled back: %v", err, err1) + } + return nil, err + } + createdBp = api.ConvertBreakpoint(bp) + log.Printf("created breakpoint: %#v", createdBp) + return createdBp, nil +} + +func (d *Debugger) AmendBreakpoint(amend *api.Breakpoint) error { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + original := d.findBreakpoint(amend.ID) + if original == nil { + return fmt.Errorf("no breakpoint with ID %d", amend.ID) + } + if err := api.ValidBreakpointName(amend.Name); err != nil { + return err + } + return copyBreakpointInfo(original, amend) +} + +func (d *Debugger) CancelNext() error { + return d.target.ClearInternalBreakpoints() +} + +func copyBreakpointInfo(bp *proc.Breakpoint, requested *api.Breakpoint) (err error) { + bp.Name = requested.Name + bp.Tracepoint = requested.Tracepoint + bp.Goroutine = requested.Goroutine + bp.Stacktrace = requested.Stacktrace + bp.Variables = requested.Variables + bp.LoadArgs = api.LoadConfigToProc(requested.LoadArgs) + bp.LoadLocals = api.LoadConfigToProc(requested.LoadLocals) + bp.Cond = nil + if requested.Cond != "" { + bp.Cond, err = parser.ParseExpr(requested.Cond) + } + return err +} + +// ClearBreakpoint clears a breakpoint. +func (d *Debugger) ClearBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + var clearedBp *api.Breakpoint + bp, err := d.target.ClearBreakpoint(requestedBp.Addr) + if err != nil { + return nil, fmt.Errorf("Can't clear breakpoint @%x: %s", requestedBp.Addr, err) + } + clearedBp = api.ConvertBreakpoint(bp) + log.Printf("cleared breakpoint: %#v", clearedBp) + return clearedBp, err +} + +// Breakpoints returns the list of current breakpoints. +func (d *Debugger) Breakpoints() []*api.Breakpoint { + d.processMutex.Lock() + defer d.processMutex.Unlock() + return d.breakpoints() +} + +func (d *Debugger) breakpoints() []*api.Breakpoint { + bps := []*api.Breakpoint{} + for _, bp := range d.target.Breakpoints() { + if bp.Internal() { + continue + } + bps = append(bps, api.ConvertBreakpoint(bp)) + } + return bps +} + +// FindBreakpoint returns the breakpoint specified by 'id'. +func (d *Debugger) FindBreakpoint(id int) *api.Breakpoint { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + bp := d.findBreakpoint(id) + if bp == nil { + return nil + } + return api.ConvertBreakpoint(bp) +} + +func (d *Debugger) findBreakpoint(id int) *proc.Breakpoint { + for _, bp := range d.target.Breakpoints() { + if bp.ID == id { + return bp + } + } + return nil +} + +// FindBreakpointByName returns the breakpoint specified by 'name' +func (d *Debugger) FindBreakpointByName(name string) *api.Breakpoint { + d.processMutex.Lock() + defer d.processMutex.Unlock() + return d.findBreakpointByName(name) +} + +func (d *Debugger) findBreakpointByName(name string) *api.Breakpoint { + for _, bp := range d.breakpoints() { + if bp.Name == name { + return bp + } + } + return nil +} + +// Threads returns the threads of the target process. +func (d *Debugger) Threads() ([]*api.Thread, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + if d.target.Exited() { + return nil, &proc.ProcessExitedError{} + } + threads := []*api.Thread{} + for _, th := range d.target.Threads() { + threads = append(threads, api.ConvertThread(th)) + } + return threads, nil +} + +// FindThread returns the thread for the given 'id'. +func (d *Debugger) FindThread(id int) (*api.Thread, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + if d.target.Exited() { + return nil, &proc.ProcessExitedError{} + } + + for _, th := range d.target.Threads() { + if th.ID == id { + return api.ConvertThread(th), nil + } + } + return nil, nil +} + +// Command handles commands which control the debugger lifecycle +func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, error) { + var err error + + if command.Name == api.Halt { + // RequestManualStop does not invoke any ptrace syscalls, so it's safe to + // access the process directly. + log.Print("halting") + err = d.target.RequestManualStop() + } + + d.processMutex.Lock() + defer d.processMutex.Unlock() + + switch command.Name { + case api.Continue: + log.Print("continuing") + err = d.target.Continue() + if err != nil { + if exitedErr, exited := err.(proc.ProcessExitedError); exited { + state := &api.DebuggerState{} + state.Exited = true + state.ExitStatus = exitedErr.Status + state.Err = errors.New(exitedErr.Error()) + return state, nil + } + return nil, err + } + state, stateErr := d.state() + if stateErr != nil { + return state, stateErr + } + err = d.collectBreakpointInformation(state) + return state, err + + case api.Next: + log.Print("nexting") + err = d.target.Next() + case api.Step: + log.Print("stepping") + err = d.target.Step() + case api.StepInstruction: + log.Print("single stepping") + err = d.target.StepInstruction() + case api.StepOut: + log.Print("step out") + err = d.target.StepOut() + case api.SwitchThread: + log.Printf("switching to thread %d", command.ThreadID) + err = d.target.SwitchThread(command.ThreadID) + case api.SwitchGoroutine: + log.Printf("switching to goroutine %d", command.GoroutineID) + err = d.target.SwitchGoroutine(command.GoroutineID) + case api.Halt: + // RequestManualStop already called + } + if err != nil { + return nil, err + } + return d.state() +} + +func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error { + if state == nil { + return nil + } + + for i := range state.Threads { + if state.Threads[i].Breakpoint == nil { + continue + } + + bp := state.Threads[i].Breakpoint + bpi := &api.BreakpointInfo{} + state.Threads[i].BreakpointInfo = bpi + + if bp.Goroutine { + g, err := d.target.CurrentThread().GetG() + if err != nil { + return err + } + bpi.Goroutine = api.ConvertGoroutine(g) + } + + if bp.Stacktrace > 0 { + rawlocs, err := d.target.CurrentThread().Stacktrace(bp.Stacktrace) + if err != nil { + return err + } + bpi.Stacktrace, err = d.convertStacktrace(rawlocs, nil) + if err != nil { + return err + } + } + + s, err := d.target.Threads()[state.Threads[i].ID].Scope() + if err != nil { + return err + } + + if len(bp.Variables) > 0 { + bpi.Variables = make([]api.Variable, len(bp.Variables)) + } + for i := range bp.Variables { + v, err := s.EvalVariable(bp.Variables[i], proc.LoadConfig{true, 1, 64, 64, -1}) + if err != nil { + return err + } + bpi.Variables[i] = *api.ConvertVar(v) + } + if bp.LoadArgs != nil { + if vars, err := s.FunctionArguments(*api.LoadConfigToProc(bp.LoadArgs)); err == nil { + bpi.Arguments = convertVars(vars) + } + } + if bp.LoadLocals != nil { + if locals, err := s.LocalVariables(*api.LoadConfigToProc(bp.LoadLocals)); err == nil { + bpi.Locals = convertVars(locals) + } + } + } + + return nil +} + +// Sources returns a list of the source files for target binary. +func (d *Debugger) Sources(filter string) ([]string, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + regex, err := regexp.Compile(filter) + if err != nil { + return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) + } + + files := []string{} + for f := range d.target.Sources() { + if regex.Match([]byte(f)) { + files = append(files, f) + } + } + return files, nil +} + +// Functions returns a list of functions in the target process. +func (d *Debugger) Functions(filter string) ([]string, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + return regexFilterFuncs(filter, d.target.Funcs()) +} + +func (d *Debugger) Types(filter string) ([]string, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + regex, err := regexp.Compile(filter) + if err != nil { + return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) + } + + types, err := d.target.Types() + if err != nil { + return nil, err + } + + r := make([]string, 0, len(types)) + for _, typ := range types { + if regex.Match([]byte(typ)) { + r = append(r, typ) + } + } + + return r, nil +} + +func regexFilterFuncs(filter string, allFuncs []gosym.Func) ([]string, error) { + regex, err := regexp.Compile(filter) + if err != nil { + return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) + } + + funcs := []string{} + for _, f := range allFuncs { + if f.Sym != nil && regex.Match([]byte(f.Name)) { + funcs = append(funcs, f.Name) + } + } + return funcs, nil +} + +// PackageVariables returns a list of package variables for the thread, +// optionally regexp filtered using regexp described in 'filter'. +func (d *Debugger) PackageVariables(threadID int, filter string, cfg proc.LoadConfig) ([]api.Variable, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + regex, err := regexp.Compile(filter) + if err != nil { + return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) + } + + vars := []api.Variable{} + thread, found := d.target.Threads()[threadID] + if !found { + return nil, fmt.Errorf("couldn't find thread %d", threadID) + } + scope, err := thread.Scope() + if err != nil { + return nil, err + } + pv, err := scope.PackageVariables(cfg) + if err != nil { + return nil, err + } + for _, v := range pv { + if regex.Match([]byte(v.Name)) { + vars = append(vars, *api.ConvertVar(v)) + } + } + return vars, err +} + +// Registers returns string representation of the CPU registers. +func (d *Debugger) Registers(threadID int, floatingPoint bool) (api.Registers, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + thread, found := d.target.Threads()[threadID] + if !found { + return nil, fmt.Errorf("couldn't find thread %d", threadID) + } + regs, err := thread.Registers(floatingPoint) + if err != nil { + return nil, err + } + return api.ConvertRegisters(regs.Slice()), err +} + +func convertVars(pv []*proc.Variable) []api.Variable { + vars := make([]api.Variable, 0, len(pv)) + for _, v := range pv { + vars = append(vars, *api.ConvertVar(v)) + } + return vars +} + +// LocalVariables returns a list of the local variables. +func (d *Debugger) LocalVariables(scope api.EvalScope, cfg proc.LoadConfig) ([]api.Variable, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + s, err := d.target.ConvertEvalScope(scope.GoroutineID, scope.Frame) + if err != nil { + return nil, err + } + pv, err := s.LocalVariables(cfg) + if err != nil { + return nil, err + } + return convertVars(pv), err +} + +// FunctionArguments returns the arguments to the current function. +func (d *Debugger) FunctionArguments(scope api.EvalScope, cfg proc.LoadConfig) ([]api.Variable, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + s, err := d.target.ConvertEvalScope(scope.GoroutineID, scope.Frame) + if err != nil { + return nil, err + } + pv, err := s.FunctionArguments(cfg) + if err != nil { + return nil, err + } + return convertVars(pv), nil +} + +// EvalVariableInScope will attempt to evaluate the variable represented by 'symbol' +// in the scope provided. +func (d *Debugger) EvalVariableInScope(scope api.EvalScope, symbol string, cfg proc.LoadConfig) (*api.Variable, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + s, err := d.target.ConvertEvalScope(scope.GoroutineID, scope.Frame) + if err != nil { + return nil, err + } + v, err := s.EvalVariable(symbol, cfg) + if err != nil { + return nil, err + } + return api.ConvertVar(v), err +} + +// SetVariableInScope will set the value of the variable represented by +// 'symbol' to the value given, in the given scope. +func (d *Debugger) SetVariableInScope(scope api.EvalScope, symbol, value string) error { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + s, err := d.target.ConvertEvalScope(scope.GoroutineID, scope.Frame) + if err != nil { + return err + } + return s.SetVariable(symbol, value) +} + +// Goroutines will return a list of goroutines in the target process. +func (d *Debugger) Goroutines() ([]*api.Goroutine, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + goroutines := []*api.Goroutine{} + gs, err := d.target.GoroutinesInfo() + if err != nil { + return nil, err + } + for _, g := range gs { + goroutines = append(goroutines, api.ConvertGoroutine(g)) + } + return goroutines, err +} + +// Stacktrace returns a list of Stackframes for the given goroutine. The +// length of the returned list will be min(stack_len, depth). +// If 'full' is true, then local vars, function args, etc will be returned as well. +func (d *Debugger) Stacktrace(goroutineID, depth int, cfg *proc.LoadConfig) ([]api.Stackframe, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + var rawlocs []proc.Stackframe + + g, err := d.target.FindGoroutine(goroutineID) + if err != nil { + return nil, err + } + + if g == nil { + rawlocs, err = d.target.CurrentThread().Stacktrace(depth) + } else { + rawlocs, err = g.Stacktrace(depth) + } + if err != nil { + return nil, err + } + + return d.convertStacktrace(rawlocs, cfg) +} + +func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadConfig) ([]api.Stackframe, error) { + locations := make([]api.Stackframe, 0, len(rawlocs)) + for i := range rawlocs { + frame := api.Stackframe{Location: api.ConvertLocation(rawlocs[i].Call)} + if cfg != nil && rawlocs[i].Current.Fn != nil { + var err error + scope := rawlocs[i].Scope(d.target.CurrentThread()) + locals, err := scope.LocalVariables(*cfg) + if err != nil { + return nil, err + } + arguments, err := scope.FunctionArguments(*cfg) + if err != nil { + return nil, err + } + + frame.Locals = convertVars(locals) + frame.Arguments = convertVars(arguments) + } + locations = append(locations, frame) + } + + return locations, nil +} + +// FindLocation will find the location specified by 'locStr'. +func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Location, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + loc, err := parseLocationSpec(locStr) + if err != nil { + return nil, err + } + + s, _ := d.target.ConvertEvalScope(scope.GoroutineID, scope.Frame) + + locs, err := loc.Find(d, s, locStr) + for i := range locs { + file, line, fn := d.target.PCToLine(locs[i].PC) + locs[i].File = file + locs[i].Line = line + locs[i].Function = api.ConvertFunction(fn) + } + return locs, err +} + +// Disassembles code between startPC and endPC +// if endPC == 0 it will find the function containing startPC and disassemble the whole function +func (d *Debugger) Disassemble(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) { + d.processMutex.Lock() + defer d.processMutex.Unlock() + + if endPC == 0 { + _, _, fn := d.target.PCToLine(startPC) + if fn == nil { + return nil, fmt.Errorf("Address 0x%x does not belong to any function", startPC) + } + startPC = fn.Entry + endPC = fn.End + } + + currentGoroutine := true + thread := d.target.CurrentThread() + + if s, err := d.target.ConvertEvalScope(scope.GoroutineID, scope.Frame); err == nil { + thread = s.Thread + if scope.GoroutineID != -1 { + g, _ := s.Thread.GetG() + if g == nil || g.ID != scope.GoroutineID { + currentGoroutine = false + } + } + } + + insts, err := thread.Disassemble(startPC, endPC, currentGoroutine) + if err != nil { + return nil, err + } + disass := make(api.AsmInstructions, len(insts)) + + for i := range insts { + disass[i] = api.ConvertAsmInstruction(insts[i], insts[i].Text(proc.AssemblyFlavour(flavour))) + } + + return disass, nil +} diff --git a/vendor/github.com/derekparker/delve/service/debugger/debugger_darwin.go b/vendor/github.com/derekparker/delve/service/debugger/debugger_darwin.go new file mode 100644 index 0000000..c317718 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/debugger/debugger_darwin.go @@ -0,0 +1,15 @@ +package debugger + +import ( + "fmt" + sys "golang.org/x/sys/unix" +) + +func attachErrorMessage(pid int, err error) error { + //TODO: mention certificates? + return fmt.Errorf("could not attach to pid %d: %s", pid, err) +} + +func stopProcess(pid int) error { + return sys.Kill(pid, sys.SIGSTOP) +} diff --git a/vendor/github.com/derekparker/delve/service/debugger/debugger_linux.go b/vendor/github.com/derekparker/delve/service/debugger/debugger_linux.go new file mode 100644 index 0000000..1d567c0 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/debugger/debugger_linux.go @@ -0,0 +1,35 @@ +package debugger + +import ( + "fmt" + sys "golang.org/x/sys/unix" + "io/ioutil" + "os" + "syscall" +) + +func attachErrorMessage(pid int, err error) error { + fallbackerr := fmt.Errorf("could not attach to pid %d: %s", pid, err) + if serr, ok := err.(syscall.Errno); ok { + switch serr { + case syscall.EPERM: + bs, err := ioutil.ReadFile("/proc/sys/kernel/yama/ptrace_scope") + if err == nil && len(bs) >= 1 && bs[0] != '0' { + // Yama documentation: https://www.kernel.org/doc/Documentation/security/Yama.txt + return fmt.Errorf("Could not attach to pid %d: set /proc/sys/kernel/yama/ptrace_scope to 0", pid) + } + fi, err := os.Stat(fmt.Sprintf("/proc/%d", pid)) + if err != nil { + return fallbackerr + } + if fi.Sys().(*syscall.Stat_t).Uid != uint32(os.Getuid()) { + return fmt.Errorf("Could not attach to pid %d: current user does not own the process", pid) + } + } + } + return fallbackerr +} + +func stopProcess(pid int) error { + return sys.Kill(pid, sys.SIGSTOP) +} diff --git a/vendor/github.com/derekparker/delve/service/debugger/debugger_windows.go b/vendor/github.com/derekparker/delve/service/debugger/debugger_windows.go new file mode 100644 index 0000000..c80ce2a --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/debugger/debugger_windows.go @@ -0,0 +1,16 @@ +package debugger + +import ( + "fmt" +) + +func attachErrorMessage(pid int, err error) error { + return fmt.Errorf("could not attach to pid %d: %s", pid, err) +} + +func stopProcess(pid int) error { + // We cannot gracefully stop a process on Windows, + // so just ignore this request and let `Detach` kill + // the process. + return nil +} diff --git a/vendor/github.com/derekparker/delve/service/debugger/locations.go b/vendor/github.com/derekparker/delve/service/debugger/locations.go new file mode 100644 index 0000000..ddc5576 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/debugger/locations.go @@ -0,0 +1,411 @@ +package debugger + +import ( + "debug/gosym" + "fmt" + "go/constant" + "path/filepath" + "reflect" + "runtime" + "strconv" + "strings" + + "github.com/derekparker/delve/pkg/proc" + "github.com/derekparker/delve/service/api" +) + +const maxFindLocationCandidates = 5 + +type LocationSpec interface { + Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) +} + +type NormalLocationSpec struct { + Base string + FuncBase *FuncLocationSpec + LineOffset int +} + +type RegexLocationSpec struct { + FuncRegex string +} + +type AddrLocationSpec struct { + AddrExpr string +} + +type OffsetLocationSpec struct { + Offset int +} + +type LineLocationSpec struct { + Line int +} + +type FuncLocationSpec struct { + PackageName string + AbsolutePackage bool + ReceiverName string + PackageOrReceiverName string + BaseName string +} + +func parseLocationSpec(locStr string) (LocationSpec, error) { + rest := locStr + + malformed := func(reason string) error { + return fmt.Errorf("Malformed breakpoint location \"%s\" at %d: %s", locStr, len(locStr)-len(rest), reason) + } + + if len(rest) <= 0 { + return nil, malformed("empty string") + } + + switch rest[0] { + case '+', '-': + offset, err := strconv.Atoi(rest) + if err != nil { + return nil, malformed(err.Error()) + } + return &OffsetLocationSpec{offset}, nil + + case '/': + if rest[len(rest)-1] == '/' { + rx, rest := readRegex(rest[1:]) + if len(rest) < 0 { + return nil, malformed("non-terminated regular expression") + } + if len(rest) > 1 { + return nil, malformed("no line offset can be specified for regular expression locations") + } + return &RegexLocationSpec{rx}, nil + } else { + return parseLocationSpecDefault(locStr, rest) + } + + case '*': + return &AddrLocationSpec{rest[1:]}, nil + + default: + return parseLocationSpecDefault(locStr, rest) + } +} + +func parseLocationSpecDefault(locStr, rest string) (LocationSpec, error) { + malformed := func(reason string) error { + return fmt.Errorf("Malformed breakpoint location \"%s\" at %d: %s", locStr, len(locStr)-len(rest), reason) + } + + v := strings.Split(rest, ":") + if len(v) > 2 { + // On Windows, path may contain ":", so split only on last ":" + v = []string{strings.Join(v[0:len(v)-1], ":"), v[len(v)-1]} + } + + if len(v) == 1 { + n, err := strconv.ParseInt(v[0], 0, 64) + if err == nil { + return &LineLocationSpec{int(n)}, nil + } + } + + spec := &NormalLocationSpec{} + + spec.Base = v[0] + spec.FuncBase = parseFuncLocationSpec(spec.Base) + + if len(v) < 2 { + spec.LineOffset = -1 + return spec, nil + } + + rest = v[1] + + var err error + spec.LineOffset, err = strconv.Atoi(rest) + if err != nil || spec.LineOffset < 0 { + return nil, malformed("line offset negative or not a number") + } + + return spec, nil +} + +func readRegex(in string) (rx string, rest string) { + out := make([]rune, 0, len(in)) + escaped := false + for i, ch := range in { + if escaped { + if ch == '/' { + out = append(out, '/') + } else { + out = append(out, '\\') + out = append(out, ch) + } + escaped = false + } else { + switch ch { + case '\\': + escaped = true + case '/': + return string(out), in[i:] + default: + out = append(out, ch) + } + } + } + return string(out), "" +} + +func parseFuncLocationSpec(in string) *FuncLocationSpec { + var v []string + pathend := strings.LastIndex(in, "/") + if pathend < 0 { + v = strings.Split(in, ".") + } else { + v = strings.Split(in[pathend:], ".") + if len(v) > 0 { + v[0] = in[:pathend] + v[0] + } + } + + var spec FuncLocationSpec + switch len(v) { + case 1: + spec.BaseName = v[0] + + case 2: + spec.BaseName = v[1] + r := stripReceiverDecoration(v[0]) + if r != v[0] { + spec.ReceiverName = r + } else if strings.Index(r, "/") >= 0 { + spec.PackageName = r + } else { + spec.PackageOrReceiverName = r + } + + case 3: + spec.BaseName = v[2] + spec.ReceiverName = stripReceiverDecoration(v[1]) + spec.PackageName = v[0] + + default: + return nil + } + + if strings.HasPrefix(spec.PackageName, "/") { + spec.PackageName = spec.PackageName[1:] + spec.AbsolutePackage = true + } + + if strings.Index(spec.BaseName, "/") >= 0 || strings.Index(spec.ReceiverName, "/") >= 0 { + return nil + } + + return &spec +} + +func stripReceiverDecoration(in string) string { + if len(in) < 3 { + return in + } + if (in[0] != '(') || (in[1] != '*') || (in[len(in)-1] != ')') { + return in + } + + return in[2 : len(in)-1] +} + +func (spec *FuncLocationSpec) Match(sym *gosym.Sym) bool { + if spec.BaseName != sym.BaseName() { + return false + } + + recv := stripReceiverDecoration(sym.ReceiverName()) + if spec.ReceiverName != "" && spec.ReceiverName != recv { + return false + } + if spec.PackageName != "" { + if spec.AbsolutePackage { + if spec.PackageName != sym.PackageName() { + return false + } + } else { + if !partialPathMatch(spec.PackageName, sym.PackageName()) { + return false + } + } + } + if spec.PackageOrReceiverName != "" && !partialPathMatch(spec.PackageOrReceiverName, sym.PackageName()) && spec.PackageOrReceiverName != recv { + return false + } + return true +} + +func (loc *RegexLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) { + funcs := d.target.Funcs() + matches, err := regexFilterFuncs(loc.FuncRegex, funcs) + if err != nil { + return nil, err + } + r := make([]api.Location, 0, len(matches)) + for i := range matches { + addr, err := d.target.FindFunctionLocation(matches[i], true, 0) + if err == nil { + r = append(r, api.Location{PC: addr}) + } + } + return r, nil +} + +func (loc *AddrLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) { + if scope == nil { + addr, err := strconv.ParseInt(loc.AddrExpr, 0, 64) + if err != nil { + return nil, fmt.Errorf("could not determine current location (scope is nil)") + } + return []api.Location{{PC: uint64(addr)}}, nil + } else { + v, err := scope.EvalExpression(loc.AddrExpr, proc.LoadConfig{true, 0, 0, 0, 0}) + if err != nil { + return nil, err + } + if v.Unreadable != nil { + return nil, v.Unreadable + } + switch v.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + addr, _ := constant.Uint64Val(v.Value) + return []api.Location{{PC: addr}}, nil + case reflect.Func: + _, _, fn := d.target.PCToLine(uint64(v.Base)) + pc, err := d.target.FirstPCAfterPrologue(fn, false) + if err != nil { + return nil, err + } + return []api.Location{{PC: uint64(pc)}}, nil + default: + return nil, fmt.Errorf("wrong expression kind: %v", v.Kind) + } + } +} + +func (loc *NormalLocationSpec) FileMatch(path string) bool { + return partialPathMatch(loc.Base, path) +} + +func partialPathMatch(expr, path string) bool { + if runtime.GOOS == "windows" { + // Accept `expr` which is case-insensitive and slash-insensitive match to `path` + expr = strings.ToLower(filepath.ToSlash(expr)) + path = strings.ToLower(filepath.ToSlash(path)) + } + if len(expr) < len(path)-1 { + return strings.HasSuffix(path, expr) && (path[len(path)-len(expr)-1] == '/') + } else { + return expr == path + } +} + +type AmbiguousLocationError struct { + Location string + CandidatesString []string + CandidatesLocation []api.Location +} + +func (ale AmbiguousLocationError) Error() string { + var candidates []string + if ale.CandidatesLocation != nil { + for i := range ale.CandidatesLocation { + candidates = append(candidates, ale.CandidatesLocation[i].Function.Name) + } + + } else { + candidates = ale.CandidatesString + } + return fmt.Sprintf("Location \"%s\" ambiguous: %s…", ale.Location, strings.Join(candidates, ", ")) +} + +func (loc *NormalLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) { + funcs := d.target.Funcs() + files := d.target.Sources() + + candidates := []string{} + for file := range files { + if loc.FileMatch(file) { + candidates = append(candidates, file) + if len(candidates) >= maxFindLocationCandidates { + break + } + } + } + + if loc.FuncBase != nil { + for _, f := range funcs { + if f.Sym == nil { + continue + } + if loc.FuncBase.Match(f.Sym) { + if loc.Base == f.Name { + // if an exact match for the function name is found use it + candidates = []string{f.Name} + break + } + if len(candidates) < maxFindLocationCandidates { + candidates = append(candidates, f.Name) + } + } + } + } + + switch len(candidates) { + case 1: + var addr uint64 + var err error + if filepath.IsAbs(candidates[0]) { + if loc.LineOffset < 0 { + return nil, fmt.Errorf("Malformed breakpoint location, no line offset specified") + } + addr, err = d.target.FindFileLocation(candidates[0], loc.LineOffset) + } else { + if loc.LineOffset < 0 { + addr, err = d.target.FindFunctionLocation(candidates[0], true, 0) + } else { + addr, err = d.target.FindFunctionLocation(candidates[0], false, loc.LineOffset) + } + } + if err != nil { + return nil, err + } + return []api.Location{{PC: addr}}, nil + + case 0: + return nil, fmt.Errorf("Location \"%s\" not found", locStr) + default: + return nil, AmbiguousLocationError{Location: locStr, CandidatesString: candidates} + } +} + +func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) { + if scope == nil { + return nil, fmt.Errorf("could not determine current location (scope is nil)") + } + file, line, fn := d.target.PCToLine(scope.PC) + if fn == nil { + return nil, fmt.Errorf("could not determine current location") + } + addr, err := d.target.FindFileLocation(file, line+loc.Offset) + return []api.Location{{PC: addr}}, err +} + +func (loc *LineLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) { + if scope == nil { + return nil, fmt.Errorf("could not determine current location (scope is nil)") + } + file, _, fn := d.target.PCToLine(scope.PC) + if fn == nil { + return nil, fmt.Errorf("could not determine current location") + } + addr, err := d.target.FindFileLocation(file, loc.Line) + return []api.Location{{PC: addr}}, err +} diff --git a/vendor/github.com/derekparker/delve/service/rpc1/client.go b/vendor/github.com/derekparker/delve/service/rpc1/client.go new file mode 100644 index 0000000..43c76c4 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpc1/client.go @@ -0,0 +1,312 @@ +package rpc1 + +import ( + "errors" + "fmt" + "log" + "net/rpc" + "net/rpc/jsonrpc" + + "sync" + + "github.com/derekparker/delve/service/api" +) + +// Client is a RPC service.Client. +type RPCClient struct { + addr string + processPid int + client *rpc.Client + haltMu sync.Mutex + haltReq bool +} + +var unsupportedApiError = errors.New("unsupported") + +// NewClient creates a new RPCClient. +func NewClient(addr string) *RPCClient { + client, err := jsonrpc.Dial("tcp", addr) + if err != nil { + log.Fatal("dialing:", err) + } + return &RPCClient{ + addr: addr, + client: client, + } +} + +func (c *RPCClient) ProcessPid() int { + var pid int + c.call("ProcessPid", nil, &pid) + return pid +} + +func (c *RPCClient) Detach(kill bool) error { + return c.call("Detach", kill, nil) +} + +func (c *RPCClient) Restart() error { + return c.call("Restart", nil, nil) +} + +func (c *RPCClient) GetState() (*api.DebuggerState, error) { + state := new(api.DebuggerState) + err := c.call("State", nil, state) + return state, err +} + +func (c *RPCClient) Continue() <-chan *api.DebuggerState { + ch := make(chan *api.DebuggerState) + c.haltMu.Lock() + c.haltReq = false + c.haltMu.Unlock() + go func() { + for { + c.haltMu.Lock() + if c.haltReq { + c.haltMu.Unlock() + close(ch) + return + } + c.haltMu.Unlock() + state := new(api.DebuggerState) + err := c.call("Command", &api.DebuggerCommand{Name: api.Continue}, state) + if err != nil { + state.Err = err + } + if state.Exited { + // Error types apparently cannot be marshalled by Go correctly. Must reset error here. + state.Err = fmt.Errorf("Process %d has exited with status %d", c.ProcessPid(), state.ExitStatus) + } + ch <- state + if err != nil || state.Exited { + close(ch) + return + } + + isbreakpoint := false + istracepoint := true + for i := range state.Threads { + if state.Threads[i].Breakpoint != nil { + isbreakpoint = true + istracepoint = istracepoint && state.Threads[i].Breakpoint.Tracepoint + } + } + + if !isbreakpoint || !istracepoint { + close(ch) + return + } + } + }() + return ch +} + +func (c *RPCClient) Next() (*api.DebuggerState, error) { + state := new(api.DebuggerState) + err := c.call("Command", &api.DebuggerCommand{Name: api.Next}, state) + return state, err +} + +func (c *RPCClient) Step() (*api.DebuggerState, error) { + state := new(api.DebuggerState) + err := c.call("Command", &api.DebuggerCommand{Name: api.Step}, state) + return state, err +} + +func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) { + state := new(api.DebuggerState) + err := c.call("Command", &api.DebuggerCommand{Name: api.StepInstruction}, state) + return state, err +} + +func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) { + state := new(api.DebuggerState) + cmd := &api.DebuggerCommand{ + Name: api.SwitchThread, + ThreadID: threadID, + } + err := c.call("Command", cmd, state) + return state, err +} + +func (c *RPCClient) SwitchGoroutine(goroutineID int) (*api.DebuggerState, error) { + state := new(api.DebuggerState) + cmd := &api.DebuggerCommand{ + Name: api.SwitchGoroutine, + GoroutineID: goroutineID, + } + err := c.call("Command", cmd, state) + return state, err +} + +func (c *RPCClient) Halt() (*api.DebuggerState, error) { + state := new(api.DebuggerState) + c.haltMu.Lock() + c.haltReq = true + c.haltMu.Unlock() + err := c.call("Command", &api.DebuggerCommand{Name: api.Halt}, state) + return state, err +} + +func (c *RPCClient) GetBreakpoint(id int) (*api.Breakpoint, error) { + breakpoint := new(api.Breakpoint) + err := c.call("GetBreakpoint", id, breakpoint) + return breakpoint, err +} + +func (c *RPCClient) GetBreakpointByName(name string) (*api.Breakpoint, error) { + breakpoint := new(api.Breakpoint) + err := c.call("GetBreakpointByName", name, breakpoint) + return breakpoint, err +} + +func (c *RPCClient) CreateBreakpoint(breakPoint *api.Breakpoint) (*api.Breakpoint, error) { + newBreakpoint := new(api.Breakpoint) + err := c.call("CreateBreakpoint", breakPoint, &newBreakpoint) + return newBreakpoint, err +} + +func (c *RPCClient) ListBreakpoints() ([]*api.Breakpoint, error) { + var breakpoints []*api.Breakpoint + err := c.call("ListBreakpoints", nil, &breakpoints) + return breakpoints, err +} + +func (c *RPCClient) ClearBreakpoint(id int) (*api.Breakpoint, error) { + bp := new(api.Breakpoint) + err := c.call("ClearBreakpoint", id, bp) + return bp, err +} + +func (c *RPCClient) ClearBreakpointByName(name string) (*api.Breakpoint, error) { + bp := new(api.Breakpoint) + err := c.call("ClearBreakpointByName", name, bp) + return bp, err +} + +func (c *RPCClient) AmendBreakpoint(bp *api.Breakpoint) error { + err := c.call("AmendBreakpoint", bp, nil) + return err +} + +func (c *RPCClient) CancelNext() error { + return unsupportedApiError +} + +func (c *RPCClient) ListThreads() ([]*api.Thread, error) { + var threads []*api.Thread + err := c.call("ListThreads", nil, &threads) + return threads, err +} + +func (c *RPCClient) GetThread(id int) (*api.Thread, error) { + thread := new(api.Thread) + err := c.call("GetThread", id, &thread) + return thread, err +} + +func (c *RPCClient) EvalVariable(scope api.EvalScope, symbol string) (*api.Variable, error) { + v := new(api.Variable) + err := c.call("EvalSymbol", EvalSymbolArgs{scope, symbol}, v) + return v, err +} + +func (c *RPCClient) SetVariable(scope api.EvalScope, symbol, value string) error { + var unused int + return c.call("SetSymbol", SetSymbolArgs{scope, symbol, value}, &unused) +} + +func (c *RPCClient) ListSources(filter string) ([]string, error) { + var sources []string + err := c.call("ListSources", filter, &sources) + return sources, err +} + +func (c *RPCClient) ListFunctions(filter string) ([]string, error) { + var funcs []string + err := c.call("ListFunctions", filter, &funcs) + return funcs, err +} + +func (c *RPCClient) ListTypes(filter string) ([]string, error) { + var types []string + err := c.call("ListTypes", filter, &types) + return types, err +} + +func (c *RPCClient) ListPackageVariables(filter string) ([]api.Variable, error) { + var vars []api.Variable + err := c.call("ListPackageVars", filter, &vars) + return vars, err +} + +func (c *RPCClient) ListPackageVariablesFor(threadID int, filter string) ([]api.Variable, error) { + var vars []api.Variable + err := c.call("ListThreadPackageVars", &ThreadListArgs{Id: threadID, Filter: filter}, &vars) + return vars, err +} + +func (c *RPCClient) ListLocalVariables(scope api.EvalScope) ([]api.Variable, error) { + var vars []api.Variable + err := c.call("ListLocalVars", scope, &vars) + return vars, err +} + +func (c *RPCClient) ListRegisters() (string, error) { + var regs string + err := c.call("ListRegisters", nil, ®s) + return regs, err +} + +func (c *RPCClient) ListFunctionArgs(scope api.EvalScope) ([]api.Variable, error) { + var vars []api.Variable + err := c.call("ListFunctionArgs", scope, &vars) + return vars, err +} + +func (c *RPCClient) ListGoroutines() ([]*api.Goroutine, error) { + var goroutines []*api.Goroutine + err := c.call("ListGoroutines", nil, &goroutines) + return goroutines, err +} + +func (c *RPCClient) Stacktrace(goroutineId, depth int, full bool) ([]api.Stackframe, error) { + var locations []api.Stackframe + err := c.call("StacktraceGoroutine", &StacktraceGoroutineArgs{Id: goroutineId, Depth: depth, Full: full}, &locations) + return locations, err +} + +func (c *RPCClient) AttachedToExistingProcess() bool { + var answer bool + c.call("AttachedToExistingProcess", nil, &answer) + return answer +} + +func (c *RPCClient) FindLocation(scope api.EvalScope, loc string) ([]api.Location, error) { + var answer []api.Location + err := c.call("FindLocation", FindLocationArgs{scope, loc}, &answer) + return answer, err +} + +// Disassemble code between startPC and endPC +func (c *RPCClient) DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) { + var r api.AsmInstructions + err := c.call("Disassemble", DisassembleRequest{scope, startPC, endPC, flavour}, &r) + return r, err +} + +// Disassemble function containing pc +func (c *RPCClient) DisassemblePC(scope api.EvalScope, pc uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) { + var r api.AsmInstructions + err := c.call("Disassemble", DisassembleRequest{scope, pc, 0, flavour}, &r) + return r, err +} + +func (c *RPCClient) url(path string) string { + return fmt.Sprintf("http://%s%s", c.addr, path) +} + +func (c *RPCClient) call(method string, args, reply interface{}) error { + return c.client.Call("RPCServer."+method, args, reply) +} diff --git a/vendor/github.com/derekparker/delve/service/rpc1/readme.txtr b/vendor/github.com/derekparker/delve/service/rpc1/readme.txtr new file mode 100644 index 0000000..c25192d --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpc1/readme.txtr @@ -0,0 +1,5 @@ +This package implements version 1 of Delve's API and is only +kept here for backwards compatibility. Client.go is the old +client code used by Delve's frontend (delve/cmd/dlv), it is +only preserved here for the backwards compatibility tests in +service/test/integration1_test.go. diff --git a/vendor/github.com/derekparker/delve/service/rpc1/server.go b/vendor/github.com/derekparker/delve/service/rpc1/server.go new file mode 100644 index 0000000..02b18e4 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpc1/server.go @@ -0,0 +1,318 @@ +package rpc1 + +import ( + "errors" + "fmt" + + "github.com/derekparker/delve/pkg/proc" + "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/api" + "github.com/derekparker/delve/service/debugger" +) + +var defaultLoadConfig = proc.LoadConfig{true, 1, 64, 64, -1} + +type RPCServer struct { + // config is all the information necessary to start the debugger and server. + config *service.Config + // debugger is a debugger service. + debugger *debugger.Debugger +} + +func NewServer(config *service.Config, debugger *debugger.Debugger) *RPCServer { + return &RPCServer{config, debugger} +} + +func (s *RPCServer) ProcessPid(arg1 interface{}, pid *int) error { + *pid = s.debugger.ProcessPid() + return nil +} + +func (s *RPCServer) Detach(kill bool, ret *int) error { + return s.debugger.Detach(kill) +} + +func (s *RPCServer) Restart(arg1 interface{}, arg2 *int) error { + if s.config.AttachPid != 0 { + return errors.New("cannot restart process Delve did not create") + } + _, err := s.debugger.Restart() + return err +} + +func (s *RPCServer) State(arg interface{}, state *api.DebuggerState) error { + st, err := s.debugger.State() + if err != nil { + return err + } + *state = *st + return nil +} + +func (s *RPCServer) Command(command *api.DebuggerCommand, cb service.RPCCallback) { + st, err := s.debugger.Command(command) + cb.Return(st, err) +} + +func (s *RPCServer) GetBreakpoint(id int, breakpoint *api.Breakpoint) error { + bp := s.debugger.FindBreakpoint(id) + if bp == nil { + return fmt.Errorf("no breakpoint with id %d", id) + } + *breakpoint = *bp + return nil +} + +func (s *RPCServer) GetBreakpointByName(name string, breakpoint *api.Breakpoint) error { + bp := s.debugger.FindBreakpointByName(name) + if bp == nil { + return fmt.Errorf("no breakpoint with name %s", name) + } + *breakpoint = *bp + return nil +} + +type StacktraceGoroutineArgs struct { + Id int + Depth int + Full bool +} + +func (s *RPCServer) StacktraceGoroutine(args *StacktraceGoroutineArgs, locations *[]api.Stackframe) error { + var loadcfg *proc.LoadConfig = nil + if args.Full { + loadcfg = &defaultLoadConfig + } + locs, err := s.debugger.Stacktrace(args.Id, args.Depth, loadcfg) + if err != nil { + return err + } + *locations = locs + return nil +} + +func (s *RPCServer) ListBreakpoints(arg interface{}, breakpoints *[]*api.Breakpoint) error { + *breakpoints = s.debugger.Breakpoints() + return nil +} + +func (s *RPCServer) CreateBreakpoint(bp, newBreakpoint *api.Breakpoint) error { + createdbp, err := s.debugger.CreateBreakpoint(bp) + if err != nil { + return err + } + *newBreakpoint = *createdbp + return nil +} + +func (s *RPCServer) ClearBreakpoint(id int, breakpoint *api.Breakpoint) error { + bp := s.debugger.FindBreakpoint(id) + if bp == nil { + return fmt.Errorf("no breakpoint with id %d", id) + } + deleted, err := s.debugger.ClearBreakpoint(bp) + if err != nil { + return err + } + *breakpoint = *deleted + return nil +} + +func (s *RPCServer) ClearBreakpointByName(name string, breakpoint *api.Breakpoint) error { + bp := s.debugger.FindBreakpointByName(name) + if bp == nil { + return fmt.Errorf("no breakpoint with name %s", name) + } + deleted, err := s.debugger.ClearBreakpoint(bp) + if err != nil { + return err + } + *breakpoint = *deleted + return nil +} + +func (s *RPCServer) AmendBreakpoint(amend *api.Breakpoint, unused *int) error { + *unused = 0 + return s.debugger.AmendBreakpoint(amend) +} + +func (s *RPCServer) ListThreads(arg interface{}, threads *[]*api.Thread) (err error) { + *threads, err = s.debugger.Threads() + return err +} + +func (s *RPCServer) GetThread(id int, thread *api.Thread) error { + t, err := s.debugger.FindThread(id) + if err != nil { + return err + } + if t == nil { + return fmt.Errorf("no thread with id %d", id) + } + *thread = *t + return nil +} + +func (s *RPCServer) ListPackageVars(filter string, variables *[]api.Variable) error { + state, err := s.debugger.State() + if err != nil { + return err + } + + current := state.CurrentThread + if current == nil { + return fmt.Errorf("no current thread") + } + + vars, err := s.debugger.PackageVariables(current.ID, filter, defaultLoadConfig) + if err != nil { + return err + } + *variables = vars + return nil +} + +type ThreadListArgs struct { + Id int + Filter string +} + +func (s *RPCServer) ListThreadPackageVars(args *ThreadListArgs, variables *[]api.Variable) error { + thread, err := s.debugger.FindThread(args.Id) + if err != nil { + return err + } + if thread == nil { + return fmt.Errorf("no thread with id %d", args.Id) + } + + vars, err := s.debugger.PackageVariables(args.Id, args.Filter, defaultLoadConfig) + if err != nil { + return err + } + *variables = vars + return nil +} + +func (s *RPCServer) ListRegisters(arg interface{}, registers *string) error { + state, err := s.debugger.State() + if err != nil { + return err + } + + regs, err := s.debugger.Registers(state.CurrentThread.ID, false) + if err != nil { + return err + } + *registers = regs.String() + return nil +} + +func (s *RPCServer) ListLocalVars(scope api.EvalScope, variables *[]api.Variable) error { + vars, err := s.debugger.LocalVariables(scope, defaultLoadConfig) + if err != nil { + return err + } + *variables = vars + return nil +} + +func (s *RPCServer) ListFunctionArgs(scope api.EvalScope, variables *[]api.Variable) error { + vars, err := s.debugger.FunctionArguments(scope, defaultLoadConfig) + if err != nil { + return err + } + *variables = vars + return nil +} + +type EvalSymbolArgs struct { + Scope api.EvalScope + Symbol string +} + +func (s *RPCServer) EvalSymbol(args EvalSymbolArgs, variable *api.Variable) error { + v, err := s.debugger.EvalVariableInScope(args.Scope, args.Symbol, defaultLoadConfig) + if err != nil { + return err + } + *variable = *v + return nil +} + +type SetSymbolArgs struct { + Scope api.EvalScope + Symbol string + Value string +} + +func (s *RPCServer) SetSymbol(args SetSymbolArgs, unused *int) error { + *unused = 0 + return s.debugger.SetVariableInScope(args.Scope, args.Symbol, args.Value) +} + +func (s *RPCServer) ListSources(filter string, sources *[]string) error { + ss, err := s.debugger.Sources(filter) + if err != nil { + return err + } + *sources = ss + return nil +} + +func (s *RPCServer) ListFunctions(filter string, funcs *[]string) error { + fns, err := s.debugger.Functions(filter) + if err != nil { + return err + } + *funcs = fns + return nil +} + +func (s *RPCServer) ListTypes(filter string, types *[]string) error { + tps, err := s.debugger.Types(filter) + if err != nil { + return err + } + *types = tps + return nil +} + +func (s *RPCServer) ListGoroutines(arg interface{}, goroutines *[]*api.Goroutine) error { + gs, err := s.debugger.Goroutines() + if err != nil { + return err + } + *goroutines = gs + return nil +} + +func (c *RPCServer) AttachedToExistingProcess(arg interface{}, answer *bool) error { + if c.config.AttachPid != 0 { + *answer = true + } + return nil +} + +type FindLocationArgs struct { + Scope api.EvalScope + Loc string +} + +func (c *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error { + var err error + *answer, err = c.debugger.FindLocation(args.Scope, args.Loc) + return err +} + +type DisassembleRequest struct { + Scope api.EvalScope + StartPC, EndPC uint64 + Flavour api.AssemblyFlavour +} + +func (c *RPCServer) Disassemble(args DisassembleRequest, answer *api.AsmInstructions) error { + var err error + *answer, err = c.debugger.Disassemble(args.Scope, args.StartPC, args.EndPC, args.Flavour) + return err +} diff --git a/vendor/github.com/derekparker/delve/service/rpc2/client.go b/vendor/github.com/derekparker/delve/service/rpc2/client.go new file mode 100644 index 0000000..1489044 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpc2/client.go @@ -0,0 +1,308 @@ +package rpc2 + +import ( + "fmt" + "log" + "net/rpc" + "net/rpc/jsonrpc" + "time" + + "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/api" +) + +// Client is a RPC service.Client. +type RPCClient struct { + addr string + processPid int + client *rpc.Client +} + +// Ensure the implementation satisfies the interface. +var _ service.Client = &RPCClient{} + +// NewClient creates a new RPCClient. +func NewClient(addr string) *RPCClient { + client, err := jsonrpc.Dial("tcp", addr) + if err != nil { + log.Fatal("dialing:", err) + } + c := &RPCClient{addr: addr, client: client} + c.call("SetApiVersion", api.SetAPIVersionIn{2}, &api.SetAPIVersionOut{}) + return c +} + +func (c *RPCClient) ProcessPid() int { + out := new(ProcessPidOut) + c.call("ProcessPid", ProcessPidIn{}, out) + return out.Pid +} + +func (c *RPCClient) LastModified() time.Time { + out := new(LastModifiedOut) + c.call("LastModified", LastModifiedIn{}, out) + return out.Time +} + +func (c *RPCClient) Detach(kill bool) error { + out := new(DetachOut) + return c.call("Detach", DetachIn{kill}, out) +} + +func (c *RPCClient) Restart() ([]api.DiscardedBreakpoint, error) { + out := new(RestartOut) + err := c.call("Restart", RestartIn{}, out) + return out.DiscardedBreakpoints, err +} + +func (c *RPCClient) GetState() (*api.DebuggerState, error) { + var out StateOut + err := c.call("State", StateIn{}, &out) + return out.State, err +} + +func (c *RPCClient) Continue() <-chan *api.DebuggerState { + ch := make(chan *api.DebuggerState) + go func() { + for { + out := new(CommandOut) + err := c.call("Command", &api.DebuggerCommand{Name: api.Continue}, &out) + state := out.State + if err != nil { + state.Err = err + } + if state.Exited { + // Error types apparantly cannot be marshalled by Go correctly. Must reset error here. + state.Err = fmt.Errorf("Process %d has exited with status %d", c.ProcessPid(), state.ExitStatus) + } + ch <- &state + if err != nil || state.Exited { + close(ch) + return + } + + isbreakpoint := false + istracepoint := true + for i := range state.Threads { + if state.Threads[i].Breakpoint != nil { + isbreakpoint = true + istracepoint = istracepoint && state.Threads[i].Breakpoint.Tracepoint + } + } + + if !isbreakpoint || !istracepoint { + close(ch) + return + } + } + }() + return ch +} + +func (c *RPCClient) Next() (*api.DebuggerState, error) { + var out CommandOut + err := c.call("Command", api.DebuggerCommand{Name: api.Next}, &out) + return &out.State, err +} + +func (c *RPCClient) Step() (*api.DebuggerState, error) { + var out CommandOut + err := c.call("Command", api.DebuggerCommand{Name: api.Step}, &out) + return &out.State, err +} + +func (c *RPCClient) StepOut() (*api.DebuggerState, error) { + var out CommandOut + err := c.call("Command", &api.DebuggerCommand{Name: api.StepOut}, &out) + return &out.State, err +} + +func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) { + var out CommandOut + err := c.call("Command", api.DebuggerCommand{Name: api.StepInstruction}, &out) + return &out.State, err +} + +func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) { + var out CommandOut + cmd := api.DebuggerCommand{ + Name: api.SwitchThread, + ThreadID: threadID, + } + err := c.call("Command", cmd, &out) + return &out.State, err +} + +func (c *RPCClient) SwitchGoroutine(goroutineID int) (*api.DebuggerState, error) { + var out CommandOut + cmd := api.DebuggerCommand{ + Name: api.SwitchGoroutine, + GoroutineID: goroutineID, + } + err := c.call("Command", cmd, &out) + return &out.State, err +} + +func (c *RPCClient) Halt() (*api.DebuggerState, error) { + var out CommandOut + err := c.call("Command", api.DebuggerCommand{Name: api.Halt}, &out) + return &out.State, err +} + +func (c *RPCClient) GetBreakpoint(id int) (*api.Breakpoint, error) { + var out GetBreakpointOut + err := c.call("GetBreakpoint", GetBreakpointIn{id, ""}, &out) + return &out.Breakpoint, err +} + +func (c *RPCClient) GetBreakpointByName(name string) (*api.Breakpoint, error) { + var out GetBreakpointOut + err := c.call("GetBreakpoint", GetBreakpointIn{0, name}, &out) + return &out.Breakpoint, err +} + +func (c *RPCClient) CreateBreakpoint(breakPoint *api.Breakpoint) (*api.Breakpoint, error) { + var out CreateBreakpointOut + err := c.call("CreateBreakpoint", CreateBreakpointIn{*breakPoint}, &out) + return &out.Breakpoint, err +} + +func (c *RPCClient) ListBreakpoints() ([]*api.Breakpoint, error) { + var out ListBreakpointsOut + err := c.call("ListBreakpoints", ListBreakpointsIn{}, &out) + return out.Breakpoints, err +} + +func (c *RPCClient) ClearBreakpoint(id int) (*api.Breakpoint, error) { + var out ClearBreakpointOut + err := c.call("ClearBreakpoint", ClearBreakpointIn{id, ""}, &out) + return out.Breakpoint, err +} + +func (c *RPCClient) ClearBreakpointByName(name string) (*api.Breakpoint, error) { + var out ClearBreakpointOut + err := c.call("ClearBreakpoint", ClearBreakpointIn{0, name}, &out) + return out.Breakpoint, err +} + +func (c *RPCClient) AmendBreakpoint(bp *api.Breakpoint) error { + out := new(AmendBreakpointOut) + err := c.call("AmendBreakpoint", AmendBreakpointIn{*bp}, out) + return err +} + +func (c *RPCClient) CancelNext() error { + var out CancelNextOut + return c.call("CancelNext", CancelNextIn{}, &out) +} + +func (c *RPCClient) ListThreads() ([]*api.Thread, error) { + var out ListThreadsOut + err := c.call("ListThreads", ListThreadsIn{}, &out) + return out.Threads, err +} + +func (c *RPCClient) GetThread(id int) (*api.Thread, error) { + var out GetThreadOut + err := c.call("GetThread", GetThreadIn{id}, &out) + return out.Thread, err +} + +func (c *RPCClient) EvalVariable(scope api.EvalScope, expr string, cfg api.LoadConfig) (*api.Variable, error) { + var out EvalOut + err := c.call("Eval", EvalIn{scope, expr, &cfg}, &out) + return out.Variable, err +} + +func (c *RPCClient) SetVariable(scope api.EvalScope, symbol, value string) error { + out := new(SetOut) + return c.call("Set", SetIn{scope, symbol, value}, out) +} + +func (c *RPCClient) ListSources(filter string) ([]string, error) { + sources := new(ListSourcesOut) + err := c.call("ListSources", ListSourcesIn{filter}, sources) + return sources.Sources, err +} + +func (c *RPCClient) ListFunctions(filter string) ([]string, error) { + funcs := new(ListFunctionsOut) + err := c.call("ListFunctions", ListFunctionsIn{filter}, funcs) + return funcs.Funcs, err +} + +func (c *RPCClient) ListTypes(filter string) ([]string, error) { + types := new(ListTypesOut) + err := c.call("ListTypes", ListTypesIn{filter}, types) + return types.Types, err +} + +func (c *RPCClient) ListPackageVariables(filter string, cfg api.LoadConfig) ([]api.Variable, error) { + var out ListPackageVarsOut + err := c.call("ListPackageVars", ListPackageVarsIn{filter, cfg}, &out) + return out.Variables, err +} + +func (c *RPCClient) ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) { + var out ListLocalVarsOut + err := c.call("ListLocalVars", ListLocalVarsIn{scope, cfg}, &out) + return out.Variables, err +} + +func (c *RPCClient) ListRegisters(threadID int, includeFp bool) (api.Registers, error) { + out := new(ListRegistersOut) + err := c.call("ListRegisters", ListRegistersIn{ThreadID: threadID, IncludeFp: includeFp}, out) + return out.Regs, err +} + +func (c *RPCClient) ListFunctionArgs(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) { + var out ListFunctionArgsOut + err := c.call("ListFunctionArgs", ListFunctionArgsIn{scope, cfg}, &out) + return out.Args, err +} + +func (c *RPCClient) ListGoroutines() ([]*api.Goroutine, error) { + var out ListGoroutinesOut + err := c.call("ListGoroutines", ListGoroutinesIn{}, &out) + return out.Goroutines, err +} + +func (c *RPCClient) Stacktrace(goroutineId, depth int, cfg *api.LoadConfig) ([]api.Stackframe, error) { + var out StacktraceOut + err := c.call("Stacktrace", StacktraceIn{goroutineId, depth, false, cfg}, &out) + return out.Locations, err +} + +func (c *RPCClient) AttachedToExistingProcess() bool { + out := new(AttachedToExistingProcessOut) + c.call("AttachedToExistingProcess", AttachedToExistingProcessIn{}, out) + return out.Answer +} + +func (c *RPCClient) FindLocation(scope api.EvalScope, loc string) ([]api.Location, error) { + var out FindLocationOut + err := c.call("FindLocation", FindLocationIn{scope, loc}, &out) + return out.Locations, err +} + +// Disassemble code between startPC and endPC +func (c *RPCClient) DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) { + var out DisassembleOut + err := c.call("Disassemble", DisassembleIn{scope, startPC, endPC, flavour}, &out) + return out.Disassemble, err +} + +// Disassemble function containing pc +func (c *RPCClient) DisassemblePC(scope api.EvalScope, pc uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) { + var out DisassembleOut + err := c.call("Disassemble", DisassembleIn{scope, pc, 0, flavour}, &out) + return out.Disassemble, err +} + +func (c *RPCClient) url(path string) string { + return fmt.Sprintf("http://%s%s", c.addr, path) +} + +func (c *RPCClient) call(method string, args, reply interface{}) error { + return c.client.Call("RPCServer."+method, args, reply) +} diff --git a/vendor/github.com/derekparker/delve/service/rpc2/server.go b/vendor/github.com/derekparker/delve/service/rpc2/server.go new file mode 100644 index 0000000..51c5954 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpc2/server.go @@ -0,0 +1,575 @@ +package rpc2 + +import ( + "errors" + "fmt" + "time" + + "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/api" + "github.com/derekparker/delve/service/debugger" +) + +type RPCServer struct { + // config is all the information necessary to start the debugger and server. + config *service.Config + // debugger is a debugger service. + debugger *debugger.Debugger +} + +func NewServer(config *service.Config, debugger *debugger.Debugger) *RPCServer { + return &RPCServer{config, debugger} +} + +type ProcessPidIn struct { +} + +type ProcessPidOut struct { + Pid int +} + +// ProcessPid returns the pid of the process we are debugging. +func (s *RPCServer) ProcessPid(arg ProcessPidIn, out *ProcessPidOut) error { + out.Pid = s.debugger.ProcessPid() + return nil +} + +type LastModifiedIn struct { +} + +type LastModifiedOut struct { + Time time.Time +} + +func (s *RPCServer) LastModified(arg LastModifiedIn, out *LastModifiedOut) error { + out.Time = s.debugger.LastModified() + return nil +} + +type DetachIn struct { + Kill bool +} + +type DetachOut struct { +} + +// Detach detaches the debugger, optionally killing the process. +func (s *RPCServer) Detach(arg DetachIn, out *DetachOut) error { + return s.debugger.Detach(arg.Kill) +} + +type RestartIn struct { +} + +type RestartOut struct { + DiscardedBreakpoints []api.DiscardedBreakpoint +} + +// Restart restarts program. +func (s *RPCServer) Restart(arg RestartIn, out *RestartOut) error { + if s.config.AttachPid != 0 { + return errors.New("cannot restart process Delve did not create") + } + var err error + out.DiscardedBreakpoints, err = s.debugger.Restart() + return err +} + +type StateIn struct { +} + +type StateOut struct { + State *api.DebuggerState +} + +// State returns the current debugger state. +func (s *RPCServer) State(arg StateIn, out *StateOut) error { + st, err := s.debugger.State() + if err != nil { + return err + } + out.State = st + return nil +} + +type CommandOut struct { + State api.DebuggerState +} + +// Command interrupts, continues and steps through the program. +func (s *RPCServer) Command(command api.DebuggerCommand, cb service.RPCCallback) { + st, err := s.debugger.Command(&command) + if err != nil { + cb.Return(nil, err) + return + } + var out CommandOut + out.State = *st + cb.Return(out, nil) + return +} + +type GetBreakpointIn struct { + Id int + Name string +} + +type GetBreakpointOut struct { + Breakpoint api.Breakpoint +} + +// GetBreakpoint gets a breakpoint by Name (if Name is not an empty string) or by ID. +func (s *RPCServer) GetBreakpoint(arg GetBreakpointIn, out *GetBreakpointOut) error { + var bp *api.Breakpoint + if arg.Name != "" { + bp = s.debugger.FindBreakpointByName(arg.Name) + if bp == nil { + return fmt.Errorf("no breakpoint with name %s", arg.Name) + } + } else { + bp = s.debugger.FindBreakpoint(arg.Id) + if bp == nil { + return fmt.Errorf("no breakpoint with id %d", arg.Id) + } + } + out.Breakpoint = *bp + return nil +} + +type StacktraceIn struct { + Id int + Depth int + Full bool + Cfg *api.LoadConfig +} + +type StacktraceOut struct { + Locations []api.Stackframe +} + +// Stacktrace returns stacktrace of goroutine Id up to the specified Depth. +// +// If Full is set it will also the variable of all local variables +// and function arguments of all stack frames. +func (s *RPCServer) Stacktrace(arg StacktraceIn, out *StacktraceOut) error { + cfg := arg.Cfg + if cfg == nil && arg.Full { + cfg = &api.LoadConfig{true, 1, 64, 64, -1} + } + locs, err := s.debugger.Stacktrace(arg.Id, arg.Depth, api.LoadConfigToProc(cfg)) + if err != nil { + return err + } + out.Locations = locs + return nil +} + +type ListBreakpointsIn struct { +} + +type ListBreakpointsOut struct { + Breakpoints []*api.Breakpoint +} + +// ListBreakpoints gets all breakpoints. +func (s *RPCServer) ListBreakpoints(arg ListBreakpointsIn, out *ListBreakpointsOut) error { + out.Breakpoints = s.debugger.Breakpoints() + return nil +} + +type CreateBreakpointIn struct { + Breakpoint api.Breakpoint +} + +type CreateBreakpointOut struct { + Breakpoint api.Breakpoint +} + +// CreateBreakpoint creates a new breakpoint. +// +// - If arg.Breakpoint.File is not an empty string the breakpoint +// will be created on the specified file:line location +// +// - If arg.Breakpoint.FunctionName is not an empty string +// the breakpoint will be created on the specified function:line +// location. Note that setting a breakpoint on a function's entry point +// (line == 0) can have surprising consequences, it is advisable to +// use line = -1 instead which will skip the prologue. +// +// - Otherwise the value specified by arg.Breakpoint.Addr will be used. +func (s *RPCServer) CreateBreakpoint(arg CreateBreakpointIn, out *CreateBreakpointOut) error { + createdbp, err := s.debugger.CreateBreakpoint(&arg.Breakpoint) + if err != nil { + return err + } + out.Breakpoint = *createdbp + return nil +} + +type ClearBreakpointIn struct { + Id int + Name string +} + +type ClearBreakpointOut struct { + Breakpoint *api.Breakpoint +} + +// ClearBreakpoint deletes a breakpoint by Name (if Name is not an +// empty string) or by ID. +func (s *RPCServer) ClearBreakpoint(arg ClearBreakpointIn, out *ClearBreakpointOut) error { + var bp *api.Breakpoint + if arg.Name != "" { + bp = s.debugger.FindBreakpointByName(arg.Name) + if bp == nil { + return fmt.Errorf("no breakpoint with name %s", arg.Name) + } + } else { + bp = s.debugger.FindBreakpoint(arg.Id) + if bp == nil { + return fmt.Errorf("no breakpoint with id %d", arg.Id) + } + } + deleted, err := s.debugger.ClearBreakpoint(bp) + if err != nil { + return err + } + out.Breakpoint = deleted + return nil +} + +type AmendBreakpointIn struct { + Breakpoint api.Breakpoint +} + +type AmendBreakpointOut struct { +} + +// AmendBreakpoint allows user to update an existing breakpoint +// for example to change the information retrieved when the +// breakpoint is hit or to change, add or remove the break condition. +// +// arg.Breakpoint.ID must be a valid breakpoint ID +func (s *RPCServer) AmendBreakpoint(arg AmendBreakpointIn, out *AmendBreakpointOut) error { + return s.debugger.AmendBreakpoint(&arg.Breakpoint) +} + +type CancelNextIn struct { +} + +type CancelNextOut struct { +} + +func (s *RPCServer) CancelNext(arg CancelNextIn, out *CancelNextOut) error { + return s.debugger.CancelNext() +} + +type ListThreadsIn struct { +} + +type ListThreadsOut struct { + Threads []*api.Thread +} + +// ListThreads lists all threads. +func (s *RPCServer) ListThreads(arg ListThreadsIn, out *ListThreadsOut) (err error) { + out.Threads, err = s.debugger.Threads() + return err +} + +type GetThreadIn struct { + Id int +} + +type GetThreadOut struct { + Thread *api.Thread +} + +// GetThread gets a thread by its ID. +func (s *RPCServer) GetThread(arg GetThreadIn, out *GetThreadOut) error { + t, err := s.debugger.FindThread(arg.Id) + if err != nil { + return err + } + if t == nil { + return fmt.Errorf("no thread with id %d", arg.Id) + } + out.Thread = t + return nil +} + +type ListPackageVarsIn struct { + Filter string + Cfg api.LoadConfig +} + +type ListPackageVarsOut struct { + Variables []api.Variable +} + +// ListPackageVars lists all package variables in the context of the current thread. +func (s *RPCServer) ListPackageVars(arg ListPackageVarsIn, out *ListPackageVarsOut) error { + state, err := s.debugger.State() + if err != nil { + return err + } + + current := state.CurrentThread + if current == nil { + return fmt.Errorf("no current thread") + } + + vars, err := s.debugger.PackageVariables(current.ID, arg.Filter, *api.LoadConfigToProc(&arg.Cfg)) + if err != nil { + return err + } + out.Variables = vars + return nil +} + +type ListRegistersIn struct { + ThreadID int + IncludeFp bool +} + +type ListRegistersOut struct { + Registers string + Regs api.Registers +} + +// ListRegisters lists registers and their values. +func (s *RPCServer) ListRegisters(arg ListRegistersIn, out *ListRegistersOut) error { + if arg.ThreadID == 0 { + state, err := s.debugger.State() + if err != nil { + return err + } + arg.ThreadID = state.CurrentThread.ID + } + + regs, err := s.debugger.Registers(arg.ThreadID, arg.IncludeFp) + if err != nil { + return err + } + out.Regs = regs + out.Registers = out.Regs.String() + + return nil +} + +type ListLocalVarsIn struct { + Scope api.EvalScope + Cfg api.LoadConfig +} + +type ListLocalVarsOut struct { + Variables []api.Variable +} + +// ListLocalVars lists all local variables in scope. +func (s *RPCServer) ListLocalVars(arg ListLocalVarsIn, out *ListLocalVarsOut) error { + vars, err := s.debugger.LocalVariables(arg.Scope, *api.LoadConfigToProc(&arg.Cfg)) + if err != nil { + return err + } + out.Variables = vars + return nil +} + +type ListFunctionArgsIn struct { + Scope api.EvalScope + Cfg api.LoadConfig +} + +type ListFunctionArgsOut struct { + Args []api.Variable +} + +// ListFunctionArgs lists all arguments to the current function +func (s *RPCServer) ListFunctionArgs(arg ListFunctionArgsIn, out *ListFunctionArgsOut) error { + vars, err := s.debugger.FunctionArguments(arg.Scope, *api.LoadConfigToProc(&arg.Cfg)) + if err != nil { + return err + } + out.Args = vars + return nil +} + +type EvalIn struct { + Scope api.EvalScope + Expr string + Cfg *api.LoadConfig +} + +type EvalOut struct { + Variable *api.Variable +} + +// EvalVariable returns a variable in the specified context. +// +// See https://github.com/derekparker/delve/wiki/Expressions for +// a description of acceptable values of arg.Expr. +func (s *RPCServer) Eval(arg EvalIn, out *EvalOut) error { + cfg := arg.Cfg + if cfg == nil { + cfg = &api.LoadConfig{true, 1, 64, 64, -1} + } + v, err := s.debugger.EvalVariableInScope(arg.Scope, arg.Expr, *api.LoadConfigToProc(cfg)) + if err != nil { + return err + } + out.Variable = v + return nil +} + +type SetIn struct { + Scope api.EvalScope + Symbol string + Value string +} + +type SetOut struct { +} + +// Set sets the value of a variable. Only numerical types and +// pointers are currently supported. +func (s *RPCServer) Set(arg SetIn, out *SetOut) error { + return s.debugger.SetVariableInScope(arg.Scope, arg.Symbol, arg.Value) +} + +type ListSourcesIn struct { + Filter string +} + +type ListSourcesOut struct { + Sources []string +} + +// ListSources lists all source files in the process matching filter. +func (s *RPCServer) ListSources(arg ListSourcesIn, out *ListSourcesOut) error { + ss, err := s.debugger.Sources(arg.Filter) + if err != nil { + return err + } + out.Sources = ss + return nil +} + +type ListFunctionsIn struct { + Filter string +} + +type ListFunctionsOut struct { + Funcs []string +} + +// ListFunctions lists all functions in the process matching filter. +func (s *RPCServer) ListFunctions(arg ListFunctionsIn, out *ListFunctionsOut) error { + fns, err := s.debugger.Functions(arg.Filter) + if err != nil { + return err + } + out.Funcs = fns + return nil +} + +type ListTypesIn struct { + Filter string +} + +type ListTypesOut struct { + Types []string +} + +// ListTypes lists all types in the process matching filter. +func (s *RPCServer) ListTypes(arg ListTypesIn, out *ListTypesOut) error { + tps, err := s.debugger.Types(arg.Filter) + if err != nil { + return err + } + out.Types = tps + return nil +} + +type ListGoroutinesIn struct { +} + +type ListGoroutinesOut struct { + Goroutines []*api.Goroutine +} + +// ListGoroutines lists all goroutines. +func (s *RPCServer) ListGoroutines(arg ListGoroutinesIn, out *ListGoroutinesOut) error { + gs, err := s.debugger.Goroutines() + if err != nil { + return err + } + out.Goroutines = gs + return nil +} + +type AttachedToExistingProcessIn struct { +} + +type AttachedToExistingProcessOut struct { + Answer bool +} + +// AttachedToExistingProcess returns whether we attached to a running process or not +func (c *RPCServer) AttachedToExistingProcess(arg AttachedToExistingProcessIn, out *AttachedToExistingProcessOut) error { + if c.config.AttachPid != 0 { + out.Answer = true + } + return nil +} + +type FindLocationIn struct { + Scope api.EvalScope + Loc string +} + +type FindLocationOut struct { + Locations []api.Location +} + +// FindLocation returns concrete location information described by a location expression +// +// loc ::= : | [:] | // | (+|-) | | *
+// * can be the full path of a file or just a suffix +// * ::= .. | .(*). | . | . | (*). | +// * must be unambiguous +// * // will return a location for each function matched by regex +// * + returns a location for the line that is lines after the current line +// * - returns a location for the line that is lines before the current line +// * returns a location for a line in the current file +// * *
returns the location corresponding to the specified address +// +// NOTE: this function does not actually set breakpoints. +func (c *RPCServer) FindLocation(arg FindLocationIn, out *FindLocationOut) error { + var err error + out.Locations, err = c.debugger.FindLocation(arg.Scope, arg.Loc) + return err +} + +type DisassembleIn struct { + Scope api.EvalScope + StartPC, EndPC uint64 + Flavour api.AssemblyFlavour +} + +type DisassembleOut struct { + Disassemble api.AsmInstructions +} + +// Disassemble code. +// +// If both StartPC and EndPC are non-zero the specified range will be disassembled, otherwise the function containing StartPC will be disassembled. +// +// Scope is used to mark the instruction the specified gorutine is stopped at. +// +// Disassemble will also try to calculate the destination address of an absolute indirect CALL if it happens to be the instruction the selected goroutine is stopped at. +func (c *RPCServer) Disassemble(arg DisassembleIn, out *DisassembleOut) error { + var err error + out.Disassemble, err = c.debugger.Disassemble(arg.Scope, arg.StartPC, arg.EndPC, arg.Flavour) + return err +} diff --git a/vendor/github.com/derekparker/delve/service/rpccallback.go b/vendor/github.com/derekparker/delve/service/rpccallback.go new file mode 100644 index 0000000..9b04782 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpccallback.go @@ -0,0 +1,6 @@ +package service + +// RPCCallback is used by RPC methods to return their result asynchronously. +type RPCCallback interface { + Return(out interface{}, err error) +} diff --git a/vendor/github.com/derekparker/delve/service/rpccommon/server.go b/vendor/github.com/derekparker/delve/service/rpccommon/server.go new file mode 100644 index 0000000..765fd09 --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/rpccommon/server.go @@ -0,0 +1,409 @@ +package rpccommon + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "net" + "net/rpc" + "net/rpc/jsonrpc" + "reflect" + "runtime" + "sync" + "unicode" + "unicode/utf8" + + "github.com/derekparker/delve/pkg/version" + "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/api" + "github.com/derekparker/delve/service/debugger" + "github.com/derekparker/delve/service/rpc1" + "github.com/derekparker/delve/service/rpc2" +) + +// ServerImpl implements a JSON-RPC server that can switch between two +// versions of the API. +type ServerImpl struct { + // config is all the information necessary to start the debugger and server. + config *service.Config + // listener is used to serve HTTP. + listener net.Listener + // stopChan is used to stop the listener goroutine. + stopChan chan struct{} + // debugger is the debugger service. + debugger *debugger.Debugger + // s1 is APIv1 server. + s1 *rpc1.RPCServer + // s2 is APIv2 server. + s2 *rpc2.RPCServer + // maps of served methods, one for each supported API. + methodMaps []map[string]*methodType +} + +type RPCCallback struct { + s *ServerImpl + sending *sync.Mutex + codec rpc.ServerCodec + req rpc.Request +} + +// RPCServer implements the RPC method calls common to all versions of the API. +type RPCServer struct { + s *ServerImpl +} + +type methodType struct { + method reflect.Method + Rcvr reflect.Value + ArgType reflect.Type + ReplyType reflect.Type + Synchronous bool +} + +// NewServer creates a new RPCServer. +func NewServer(config *service.Config, logEnabled bool) *ServerImpl { + log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) + if !logEnabled { + log.SetOutput(ioutil.Discard) + } + if config.APIVersion < 2 { + log.Printf("Using API v1") + } + return &ServerImpl{ + config: config, + listener: config.Listener, + stopChan: make(chan struct{}), + } +} + +// Stop stops the JSON-RPC server. +func (s *ServerImpl) Stop(kill bool) error { + if s.config.AcceptMulti { + close(s.stopChan) + s.listener.Close() + } + return s.debugger.Detach(kill) +} + +// Restart restarts the debugger. +func (s *ServerImpl) Restart() error { + if s.config.AttachPid != 0 { + return errors.New("cannot restart process Delve did not create") + } + return s.s2.Restart(rpc2.RestartIn{}, nil) +} + +// Run starts a debugger and exposes it with an HTTP server. The debugger +// itself can be stopped with the `detach` API. Run blocks until the HTTP +// server stops. +func (s *ServerImpl) Run() error { + var err error + + if s.config.APIVersion < 2 { + s.config.APIVersion = 1 + } + if s.config.APIVersion > 2 { + return fmt.Errorf("unknown API version") + } + + // Create and start the debugger + if s.debugger, err = debugger.New(&debugger.Config{ + ProcessArgs: s.config.ProcessArgs, + AttachPid: s.config.AttachPid, + WorkingDir: s.config.WorkingDir, + }); err != nil { + return err + } + + s.s1 = rpc1.NewServer(s.config, s.debugger) + s.s2 = rpc2.NewServer(s.config, s.debugger) + + rpcServer := &RPCServer{s} + + s.methodMaps = make([]map[string]*methodType, 2) + + s.methodMaps[0] = map[string]*methodType{} + s.methodMaps[1] = map[string]*methodType{} + suitableMethods(s.s1, s.methodMaps[0]) + suitableMethods(rpcServer, s.methodMaps[0]) + suitableMethods(s.s2, s.methodMaps[1]) + suitableMethods(rpcServer, s.methodMaps[1]) + + go func() { + defer s.listener.Close() + for { + c, err := s.listener.Accept() + if err != nil { + select { + case <-s.stopChan: + // We were supposed to exit, do nothing and return + return + default: + panic(err) + } + } + go s.serveJSONCodec(c) + if !s.config.AcceptMulti { + break + } + } + }() + return nil +} + +// Precompute the reflect type for error. Can't use error directly +// because Typeof takes an empty interface value. This is annoying. +var typeOfError = reflect.TypeOf((*error)(nil)).Elem() + +// Is this an exported - upper case - name? +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// Is this type exported or a builtin? +func isExportedOrBuiltinType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + // PkgPath will be non-empty even for an exported type, + // so we need to check the type name as well. + return isExported(t.Name()) || t.PkgPath() == "" +} + +// Fills methods map with the methods of receiver that should be made +// available through the RPC interface. +// These are all the public methods of rcvr that have one of those +// two signatures: +// func (rcvr ReceiverType) Method(in InputType, out *ReplyType) error +// func (rcvr ReceiverType) Method(in InputType, cb service.RPCCallback) +func suitableMethods(rcvr interface{}, methods map[string]*methodType) { + typ := reflect.TypeOf(rcvr) + rcvrv := reflect.ValueOf(rcvr) + sname := reflect.Indirect(rcvrv).Type().Name() + if sname == "" { + log.Printf("rpc.Register: no service name for type %s", typ) + return + } + for m := 0; m < typ.NumMethod(); m++ { + method := typ.Method(m) + mname := method.Name + mtype := method.Type + // method must be exported + if method.PkgPath != "" { + continue + } + // Method needs three ins: (receive, *args, *reply) or (receiver, *args, *RPCCallback) + if mtype.NumIn() != 3 { + log.Println("method", mname, "has wrong number of ins:", mtype.NumIn()) + continue + } + // First arg need not be a pointer. + argType := mtype.In(1) + if !isExportedOrBuiltinType(argType) { + log.Println(mname, "argument type not exported:", argType) + continue + } + + replyType := mtype.In(2) + synchronous := replyType.String() != "service.RPCCallback" + + if synchronous { + // Second arg must be a pointer. + if replyType.Kind() != reflect.Ptr { + log.Println("method", mname, "reply type not a pointer:", replyType) + continue + } + // Reply type must be exported. + if !isExportedOrBuiltinType(replyType) { + log.Println("method", mname, "reply type not exported:", replyType) + continue + } + + // Method needs one out. + if mtype.NumOut() != 1 { + log.Println("method", mname, "has wrong number of outs:", mtype.NumOut()) + continue + } + // The return type of the method must be error. + if returnType := mtype.Out(0); returnType != typeOfError { + log.Println("method", mname, "returns", returnType.String(), "not error") + continue + } + } else { + // Method needs zero outs. + if mtype.NumOut() != 0 { + log.Println("method", mname, "has wrong number of outs:", mtype.NumOut()) + continue + } + } + methods[sname+"."+mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType, Synchronous: synchronous, Rcvr: rcvrv} + } + return +} + +func (s *ServerImpl) serveJSONCodec(conn io.ReadWriteCloser) { + sending := new(sync.Mutex) + codec := jsonrpc.NewServerCodec(conn) + var req rpc.Request + var resp rpc.Response + for { + req = rpc.Request{} + err := codec.ReadRequestHeader(&req) + if err != nil { + if err != io.EOF { + log.Println("rpc:", err) + } + break + } + + mtype, ok := s.methodMaps[s.config.APIVersion-1][req.ServiceMethod] + if !ok { + log.Printf("rpc: can't find method %s", req.ServiceMethod) + continue + } + + var argv, replyv reflect.Value + + // Decode the argument value. + argIsValue := false // if true, need to indirect before calling. + if mtype.ArgType.Kind() == reflect.Ptr { + argv = reflect.New(mtype.ArgType.Elem()) + } else { + argv = reflect.New(mtype.ArgType) + argIsValue = true + } + // argv guaranteed to be a pointer now. + if err = codec.ReadRequestBody(argv.Interface()); err != nil { + return + } + if argIsValue { + argv = argv.Elem() + } + + if mtype.Synchronous { + replyv = reflect.New(mtype.ReplyType.Elem()) + function := mtype.method.Func + var returnValues []reflect.Value + var errInter interface{} + func() { + defer func() { + if ierr := recover(); ierr != nil { + errInter = newInternalError(ierr, 2) + } + }() + returnValues = function.Call([]reflect.Value{mtype.Rcvr, argv, replyv}) + errInter = returnValues[0].Interface() + }() + + errmsg := "" + if errInter != nil { + errmsg = errInter.(error).Error() + } + resp = rpc.Response{} + s.sendResponse(sending, &req, &resp, replyv.Interface(), codec, errmsg) + } else { + function := mtype.method.Func + ctl := &RPCCallback{s, sending, codec, req} + go func() { + defer func() { + if ierr := recover(); ierr != nil { + ctl.Return(nil, newInternalError(ierr, 2)) + } + }() + function.Call([]reflect.Value{mtype.Rcvr, argv, reflect.ValueOf(ctl)}) + }() + } + } + codec.Close() +} + +// A value sent as a placeholder for the server's response value when the server +// receives an invalid request. It is never decoded by the client since the Response +// contains an error when it is used. +var invalidRequest = struct{}{} + +func (s *ServerImpl) sendResponse(sending *sync.Mutex, req *rpc.Request, resp *rpc.Response, reply interface{}, codec rpc.ServerCodec, errmsg string) { + resp.ServiceMethod = req.ServiceMethod + if errmsg != "" { + resp.Error = errmsg + reply = invalidRequest + } + resp.Seq = req.Seq + sending.Lock() + defer sending.Unlock() + err := codec.WriteResponse(resp, reply) + if err != nil { + log.Println("rpc: writing response:", err) + } +} + +func (cb *RPCCallback) Return(out interface{}, err error) { + errmsg := "" + if err != nil { + errmsg = err.Error() + } + var resp rpc.Response + cb.s.sendResponse(cb.sending, &cb.req, &resp, out, cb.codec, errmsg) +} + +// GetVersion returns the version of delve as well as the API version +// currently served. +func (s *RPCServer) GetVersion(args api.GetVersionIn, out *api.GetVersionOut) error { + out.DelveVersion = version.DelveVersion.String() + out.APIVersion = s.s.config.APIVersion + return nil +} + +// Changes version of the API being served. +func (s *RPCServer) SetApiVersion(args api.SetAPIVersionIn, out *api.SetAPIVersionOut) error { + if args.APIVersion < 2 { + args.APIVersion = 1 + } + if args.APIVersion > 2 { + return fmt.Errorf("unknown API version") + } + s.s.config.APIVersion = args.APIVersion + return nil +} + +type internalError struct { + Err interface{} + Stack []internalErrorFrame +} + +type internalErrorFrame struct { + Pc uintptr + Func string + File string + Line int +} + +func newInternalError(ierr interface{}, skip int) *internalError { + r := &internalError{ierr, nil} + for i := skip; ; i++ { + pc, file, line, ok := runtime.Caller(i) + if !ok { + break + } + fname := "" + fn := runtime.FuncForPC(pc) + if fn != nil { + fname = fn.Name() + } + r.Stack = append(r.Stack, internalErrorFrame{pc, fname, file, line}) + } + return r +} + +func (err *internalError) Error() string { + var out bytes.Buffer + fmt.Fprintf(&out, "Internal debugger error: %v\n", err.Err) + for _, frame := range err.Stack { + fmt.Fprintf(&out, "%s (%#x)\n\t%s:%d\n", frame.Func, frame.Pc, frame.File, frame.Line) + } + return out.String() +} diff --git a/vendor/github.com/derekparker/delve/service/server.go b/vendor/github.com/derekparker/delve/service/server.go new file mode 100644 index 0000000..20a364b --- /dev/null +++ b/vendor/github.com/derekparker/delve/service/server.go @@ -0,0 +1,8 @@ +package service + +// Server represents a server for a remote client +// to connect to. +type Server interface { + Run() error + Stop(bool) error +} diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md index 9d71959..33c3d2b 100644 --- a/vendor/github.com/gorilla/websocket/README.md +++ b/vendor/github.com/gorilla/websocket/README.md @@ -3,6 +3,9 @@ Gorilla WebSocket is a [Go](http://golang.org/) implementation of the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. +[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket) +[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) + ### Documentation * [API Reference](http://godoc.org/github.com/gorilla/websocket) @@ -43,7 +46,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn Send pings and receive pongsYesNo Get the type of a received data messageYesYes, see note 2 Other Features -Limit size of received messageYesNo +Compression ExtensionsExperimentalNo Read message using io.ReaderYesNo, see note 3 Write message using io.WriteCloserYesNo, see note 3 diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go index 879d33e..eb20640 100644 --- a/vendor/github.com/gorilla/websocket/client.go +++ b/vendor/github.com/gorilla/websocket/client.go @@ -23,6 +23,8 @@ import ( // invalid. var ErrBadHandshake = errors.New("websocket: bad handshake") +var errInvalidCompression = errors.New("websocket: invalid compression negotiation") + // NewClient creates a new client connection using the given net connection. // The URL u specifies the host and request URI. Use requestHeader to specify // the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies @@ -64,12 +66,24 @@ type Dialer struct { // HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration - // Input and output buffer sizes. If the buffer size is zero, then a - // default value of 4096 is used. + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // size is zero, then a useful default size is used. The I/O buffer sizes + // do not limit the size of the messages that can be sent or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the client's requested subprotocols. Subprotocols []string + + // EnableCompression specifies if the client should attempt to negotiate + // per message compression (RFC 7692). Setting this value to true does not + // guarantee that compression will be supported. Currently only "no context + // takeover" modes are supported. + EnableCompression bool + + // Jar specifies the cookie jar. + // If Jar is nil, cookies are not sent in requests and ignored + // in responses. + Jar http.CookieJar } var errMalformedURL = errors.New("malformed ws or wss URL") @@ -83,7 +97,6 @@ func parseURL(s string) (*url.URL, error) { // // ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ] // wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ] - var u url.URL switch { case strings.HasPrefix(s, "ws://"): @@ -193,6 +206,13 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re Host: u.Host, } + // Set the cookies present in the cookie jar of the dialer + if d.Jar != nil { + for _, cookie := range d.Jar.Cookies(u) { + req.AddCookie(cookie) + } + } + // Set the request headers using the capitalization for names and values in // RFC examples. Although the capitalization shouldn't matter, there are // servers that depend on it. The Header.Set method is not used because the @@ -214,6 +234,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re k == "Connection" || k == "Sec-Websocket-Key" || k == "Sec-Websocket-Version" || + k == "Sec-Websocket-Extensions" || (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0): return nil, nil, errors.New("websocket: duplicate header not allowed: " + k) default: @@ -221,6 +242,10 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re } } + if d.EnableCompression { + req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover") + } + hostPort, hostNoPort := hostPortNoPort(u) var proxyURL *url.URL @@ -324,6 +349,13 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re if err != nil { return nil, nil, err } + + if d.Jar != nil { + if rc := resp.Cookies(); len(rc) > 0 { + d.Jar.SetCookies(u, rc) + } + } + if resp.StatusCode != 101 || !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || @@ -337,6 +369,20 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re return nil, resp, ErrBadHandshake } + for _, ext := range parseExtensions(req.Header) { + if ext[""] != "permessage-deflate" { + continue + } + _, snct := ext["server_no_context_takeover"] + _, cnct := ext["client_no_context_takeover"] + if !snct || !cnct { + return nil, resp, errInvalidCompression + } + conn.newCompressionWriter = compressNoContextTakeover + conn.newDecompressionReader = decompressNoContextTakeover + break + } + resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") @@ -344,32 +390,3 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re netConn = nil // to avoid close in defer. return conn, resp, nil } - -// cloneTLSConfig clones all public fields except the fields -// SessionTicketsDisabled and SessionTicketKey. This avoids copying the -// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a -// config in active use. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - } -} diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go new file mode 100644 index 0000000..4f0d943 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client_clone.go @@ -0,0 +1,16 @@ +// Copyright 2013 The Gorilla WebSocket 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 go1.8 + +package websocket + +import "crypto/tls" + +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return cfg.Clone() +} diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go new file mode 100644 index 0000000..babb007 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client_clone_legacy.go @@ -0,0 +1,38 @@ +// Copyright 2013 The Gorilla WebSocket 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 !go1.8 + +package websocket + +import "crypto/tls" + +// cloneTLSConfig clones all public fields except the fields +// SessionTicketsDisabled and SessionTicketKey. This avoids copying the +// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a +// config in active use. +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return &tls.Config{ + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + } +} diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go new file mode 100644 index 0000000..813ffb1 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/compression.go @@ -0,0 +1,148 @@ +// Copyright 2017 The Gorilla WebSocket 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 websocket + +import ( + "compress/flate" + "errors" + "io" + "strings" + "sync" +) + +const ( + minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6 + maxCompressionLevel = flate.BestCompression + defaultCompressionLevel = 1 +) + +var ( + flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool + flateReaderPool = sync.Pool{New: func() interface{} { + return flate.NewReader(nil) + }} +) + +func decompressNoContextTakeover(r io.Reader) io.ReadCloser { + const tail = + // Add four bytes as specified in RFC + "\x00\x00\xff\xff" + + // Add final block to squelch unexpected EOF error from flate reader. + "\x01\x00\x00\xff\xff" + + fr, _ := flateReaderPool.Get().(io.ReadCloser) + fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) + return &flateReadWrapper{fr} +} + +func isValidCompressionLevel(level int) bool { + return minCompressionLevel <= level && level <= maxCompressionLevel +} + +func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser { + p := &flateWriterPools[level-minCompressionLevel] + tw := &truncWriter{w: w} + fw, _ := p.Get().(*flate.Writer) + if fw == nil { + fw, _ = flate.NewWriter(tw, level) + } else { + fw.Reset(tw) + } + return &flateWriteWrapper{fw: fw, tw: tw, p: p} +} + +// truncWriter is an io.Writer that writes all but the last four bytes of the +// stream to another io.Writer. +type truncWriter struct { + w io.WriteCloser + n int + p [4]byte +} + +func (w *truncWriter) Write(p []byte) (int, error) { + n := 0 + + // fill buffer first for simplicity. + if w.n < len(w.p) { + n = copy(w.p[w.n:], p) + p = p[n:] + w.n += n + if len(p) == 0 { + return n, nil + } + } + + m := len(p) + if m > len(w.p) { + m = len(w.p) + } + + if nn, err := w.w.Write(w.p[:m]); err != nil { + return n + nn, err + } + + copy(w.p[:], w.p[m:]) + copy(w.p[len(w.p)-m:], p[len(p)-m:]) + nn, err := w.w.Write(p[:len(p)-m]) + return n + nn, err +} + +type flateWriteWrapper struct { + fw *flate.Writer + tw *truncWriter + p *sync.Pool +} + +func (w *flateWriteWrapper) Write(p []byte) (int, error) { + if w.fw == nil { + return 0, errWriteClosed + } + return w.fw.Write(p) +} + +func (w *flateWriteWrapper) Close() error { + if w.fw == nil { + return errWriteClosed + } + err1 := w.fw.Flush() + w.p.Put(w.fw) + w.fw = nil + if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { + return errors.New("websocket: internal error, unexpected bytes at end of flate stream") + } + err2 := w.tw.w.Close() + if err1 != nil { + return err1 + } + return err2 +} + +type flateReadWrapper struct { + fr io.ReadCloser +} + +func (r *flateReadWrapper) Read(p []byte) (int, error) { + if r.fr == nil { + return 0, io.ErrClosedPipe + } + n, err := r.fr.Read(p) + if err == io.EOF { + // Preemptively place the reader back in the pool. This helps with + // scenarios where the application does not call NextReader() soon after + // this final read. + r.Close() + } + return n, err +} + +func (r *flateReadWrapper) Close() error { + if r.fr == nil { + return io.ErrClosedPipe + } + err := r.fr.Close() + flateReaderPool.Put(r.fr) + r.fr = nil + return err +} diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go index 794c2ef..97e1dba 100644 --- a/vendor/github.com/gorilla/websocket/conn.go +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -13,16 +13,25 @@ import ( "math/rand" "net" "strconv" + "sync" "time" "unicode/utf8" ) const ( + // Frame header byte 0 bits from Section 5.2 of RFC 6455 + finalBit = 1 << 7 + rsv1Bit = 1 << 6 + rsv2Bit = 1 << 5 + rsv3Bit = 1 << 4 + + // Frame header byte 1 bits from Section 5.2 of RFC 6455 + maskBit = 1 << 7 + maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask maxControlFramePayloadSize = 125 - finalBit = 1 << 7 - maskBit = 1 << 7 - writeWait = time.Second + + writeWait = time.Second defaultReadBufferSize = 4096 defaultWriteBufferSize = 4096 @@ -172,6 +181,11 @@ var ( errInvalidControlFrame = errors.New("websocket: invalid control frame") ) +func newMaskKey() [4]byte { + n := rand.Uint32() + return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} +} + func hideTempErr(err error) error { if e, ok := err.(net.Error); ok && e.Temporary() { err = &netError{msg: e.Error(), timeout: e.Timeout()} @@ -210,39 +224,28 @@ func isValidReceivedCloseCode(code int) bool { return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999) } -func maskBytes(key [4]byte, pos int, b []byte) int { - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - return pos & 3 -} - -func newMaskKey() [4]byte { - n := rand.Uint32() - return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} -} - -// Conn represents a WebSocket connection. +// The Conn type represents a WebSocket connection. type Conn struct { conn net.Conn isServer bool subprotocol string // Write fields - mu chan bool // used as mutex to protect write to conn and closeSent - closeSent bool // true if close message was sent + mu chan bool // used as mutex to protect write to conn + writeBuf []byte // frame is constructed in this buffer. + writeDeadline time.Time + writer io.WriteCloser // the current writer returned to the application + isWriting bool // for best-effort concurrent write detection - // Message writer fields. - writeErr error - writeBuf []byte // frame is constructed in this buffer. - writePos int // end of data in writeBuf. - writeFrameType int // type of the current frame. - writeDeadline time.Time - isWriting bool // for best-effort concurrent write detection - messageWriter *messageWriter // the current writer + writeErrMu sync.Mutex + writeErr error + + enableWriteCompression bool + compressionLevel int + newCompressionWriter func(io.WriteCloser, int) io.WriteCloser // Read fields + reader io.ReadCloser // the current reader returned to the application readErr error br *bufio.Reader readRemaining int64 // bytes remaining in current frame. @@ -253,34 +256,83 @@ type Conn struct { readMaskKey [4]byte handlePong func(string) error handlePing func(string) error + handleClose func(int, string) error readErrCount int - messageReader *messageReader // the current reader + messageReader *messageReader // the current low-level reader + + readDecompress bool // whether last read frame had RSV1 set + newDecompressionReader func(io.Reader) io.ReadCloser } func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn { + return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil) +} + +type writeHook struct { + p []byte +} + +func (wh *writeHook) Write(p []byte) (int, error) { + wh.p = p + return len(p), nil +} + +func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn { mu := make(chan bool, 1) mu <- true - if readBufferSize == 0 { - readBufferSize = defaultReadBufferSize + var br *bufio.Reader + if readBufferSize == 0 && brw != nil && brw.Reader != nil { + // Reuse the supplied bufio.Reader if the buffer has a useful size. + // This code assumes that peek on a reader returns + // bufio.Reader.buf[:0]. + brw.Reader.Reset(conn) + if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 { + br = brw.Reader + } } - if readBufferSize < maxControlFramePayloadSize { - readBufferSize = maxControlFramePayloadSize + if br == nil { + if readBufferSize == 0 { + readBufferSize = defaultReadBufferSize + } + if readBufferSize < maxControlFramePayloadSize { + readBufferSize = maxControlFramePayloadSize + } + br = bufio.NewReaderSize(conn, readBufferSize) } - if writeBufferSize == 0 { - writeBufferSize = defaultWriteBufferSize + + var writeBuf []byte + if writeBufferSize == 0 && brw != nil && brw.Writer != nil { + // Use the bufio.Writer's buffer if the buffer has a useful size. This + // code assumes that bufio.Writer.buf[:1] is passed to the + // bufio.Writer's underlying writer. + var wh writeHook + brw.Writer.Reset(&wh) + brw.Writer.WriteByte(0) + brw.Flush() + if cap(wh.p) >= maxFrameHeaderSize+256 { + writeBuf = wh.p[:cap(wh.p)] + } + } + + if writeBuf == nil { + if writeBufferSize == 0 { + writeBufferSize = defaultWriteBufferSize + } + writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize) } c := &Conn{ - isServer: isServer, - br: bufio.NewReaderSize(conn, readBufferSize), - conn: conn, - mu: mu, - readFinal: true, - writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize), - writeFrameType: noFrame, - writePos: maxFrameHeaderSize, + isServer: isServer, + br: br, + conn: conn, + mu: mu, + readFinal: true, + writeBuf: writeBuf, + enableWriteCompression: true, + compressionLevel: defaultCompressionLevel, } + c.SetCloseHandler(nil) c.SetPingHandler(nil) c.SetPongHandler(nil) return c @@ -308,29 +360,40 @@ func (c *Conn) RemoteAddr() net.Addr { // Write methods +func (c *Conn) writeFatal(err error) error { + err = hideTempErr(err) + c.writeErrMu.Lock() + if c.writeErr == nil { + c.writeErr = err + } + c.writeErrMu.Unlock() + return err +} + func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error { <-c.mu defer func() { c.mu <- true }() - if c.closeSent { - return ErrCloseSent - } else if frameType == CloseMessage { - c.closeSent = true + c.writeErrMu.Lock() + err := c.writeErr + c.writeErrMu.Unlock() + if err != nil { + return err } c.conn.SetWriteDeadline(deadline) for _, buf := range bufs { if len(buf) > 0 { - n, err := c.conn.Write(buf) - if n != len(buf) { - // Close on partial write. - c.conn.Close() - } + _, err := c.conn.Write(buf) if err != nil { - return err + return c.writeFatal(err) } } } + + if frameType == CloseMessage { + c.writeFatal(ErrCloseSent) + } return nil } @@ -379,18 +442,41 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er } defer func() { c.mu <- true }() - if c.closeSent { - return ErrCloseSent - } else if messageType == CloseMessage { - c.closeSent = true + c.writeErrMu.Lock() + err := c.writeErr + c.writeErrMu.Unlock() + if err != nil { + return err } c.conn.SetWriteDeadline(deadline) - n, err := c.conn.Write(buf) - if n != 0 && n != len(buf) { - c.conn.Close() + _, err = c.conn.Write(buf) + if err != nil { + return c.writeFatal(err) } - return hideTempErr(err) + if messageType == CloseMessage { + c.writeFatal(ErrCloseSent) + } + return err +} + +func (c *Conn) prepWrite(messageType int) error { + // Close previous writer if not already closed by the application. It's + // probably better to return an error in this situation, but we cannot + // change this without breaking existing applications. + if c.writer != nil { + c.writer.Close() + c.writer = nil + } + + if !isControl(messageType) && !isData(messageType) { + return errBadWriteOpCode + } + + c.writeErrMu.Lock() + err := c.writeErr + c.writeErrMu.Unlock() + return err } // NextWriter returns a writer for the next message to send. The writer's Close @@ -399,42 +485,61 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er // There can be at most one open writer on a connection. NextWriter closes the // previous writer if the application has not already done so. func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { - if c.writeErr != nil { - return nil, c.writeErr + if err := c.prepWrite(messageType); err != nil { + return nil, err } - if c.writeFrameType != noFrame { - if err := c.flushFrame(true, nil); err != nil { - return nil, err - } + mw := &messageWriter{ + c: c, + frameType: messageType, + pos: maxFrameHeaderSize, } - - if !isControl(messageType) && !isData(messageType) { - return nil, errBadWriteOpCode + c.writer = mw + if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { + w := c.newCompressionWriter(c.writer, c.compressionLevel) + mw.compress = true + c.writer = w } - - c.writeFrameType = messageType - w := &messageWriter{c} - c.messageWriter = w - return w, nil + return c.writer, nil } -func (c *Conn) flushFrame(final bool, extra []byte) error { - length := c.writePos - maxFrameHeaderSize + len(extra) +type messageWriter struct { + c *Conn + compress bool // whether next call to flushFrame should set RSV1 + pos int // end of data in writeBuf. + frameType int // type of the current frame. + err error +} + +func (w *messageWriter) fatal(err error) error { + if w.err != nil { + w.err = err + w.c.writer = nil + } + return err +} + +// flushFrame writes buffered data and extra as a frame to the network. The +// final argument indicates that this is the last frame in the message. +func (w *messageWriter) flushFrame(final bool, extra []byte) error { + c := w.c + length := w.pos - maxFrameHeaderSize + len(extra) // Check for invalid control frames. - if isControl(c.writeFrameType) && + if isControl(w.frameType) && (!final || length > maxControlFramePayloadSize) { - c.messageWriter = nil - c.writeFrameType = noFrame - c.writePos = maxFrameHeaderSize - return errInvalidControlFrame + return w.fatal(errInvalidControlFrame) } - b0 := byte(c.writeFrameType) + b0 := byte(w.frameType) if final { b0 |= finalBit } + if w.compress { + b0 |= rsv1Bit + } + w.compress = false + b1 := byte(0) if !c.isServer { b1 |= maskBit @@ -466,10 +571,9 @@ func (c *Conn) flushFrame(final bool, extra []byte) error { if !c.isServer { key := newMaskKey() copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) - maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:c.writePos]) + maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos]) if len(extra) > 0 { - c.writeErr = errors.New("websocket: internal error, extra used in client mode") - return c.writeErr + return c.writeFatal(errors.New("websocket: internal error, extra used in client mode")) } } @@ -482,43 +586,35 @@ func (c *Conn) flushFrame(final bool, extra []byte) error { } c.isWriting = true - c.writeErr = c.write(c.writeFrameType, c.writeDeadline, c.writeBuf[framePos:c.writePos], extra) + err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra) if !c.isWriting { panic("concurrent write to websocket connection") } c.isWriting = false - // Setup for next frame. - c.writePos = maxFrameHeaderSize - c.writeFrameType = continuationFrame + if err != nil { + return w.fatal(err) + } + if final { - c.messageWriter = nil - c.writeFrameType = noFrame + c.writer = nil + return nil } - return c.writeErr -} -type messageWriter struct{ c *Conn } - -func (w *messageWriter) err() error { - c := w.c - if c.messageWriter != w { - return errWriteClosed - } - if c.writeErr != nil { - return c.writeErr - } + // Setup for next frame. + w.pos = maxFrameHeaderSize + w.frameType = continuationFrame return nil } func (w *messageWriter) ncopy(max int) (int, error) { - n := len(w.c.writeBuf) - w.c.writePos + n := len(w.c.writeBuf) - w.pos if n <= 0 { - if err := w.c.flushFrame(false, nil); err != nil { + if err := w.flushFrame(false, nil); err != nil { return 0, err } - n = len(w.c.writeBuf) - w.c.writePos + n = len(w.c.writeBuf) - w.pos } if n > max { n = max @@ -526,14 +622,14 @@ func (w *messageWriter) ncopy(max int) (int, error) { return n, nil } -func (w *messageWriter) write(final bool, p []byte) (int, error) { - if err := w.err(); err != nil { - return 0, err +func (w *messageWriter) Write(p []byte) (int, error) { + if w.err != nil { + return 0, w.err } if len(p) > 2*len(w.c.writeBuf) && w.c.isServer { // Don't buffer large messages. - err := w.c.flushFrame(final, p) + err := w.flushFrame(false, p) if err != nil { return 0, err } @@ -546,20 +642,16 @@ func (w *messageWriter) write(final bool, p []byte) (int, error) { if err != nil { return 0, err } - copy(w.c.writeBuf[w.c.writePos:], p[:n]) - w.c.writePos += n + copy(w.c.writeBuf[w.pos:], p[:n]) + w.pos += n p = p[n:] } return nn, nil } -func (w *messageWriter) Write(p []byte) (int, error) { - return w.write(false, p) -} - func (w *messageWriter) WriteString(p string) (int, error) { - if err := w.err(); err != nil { - return 0, err + if w.err != nil { + return 0, w.err } nn := len(p) @@ -568,27 +660,27 @@ func (w *messageWriter) WriteString(p string) (int, error) { if err != nil { return 0, err } - copy(w.c.writeBuf[w.c.writePos:], p[:n]) - w.c.writePos += n + copy(w.c.writeBuf[w.pos:], p[:n]) + w.pos += n p = p[n:] } return nn, nil } func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) { - if err := w.err(); err != nil { - return 0, err + if w.err != nil { + return 0, w.err } for { - if w.c.writePos == len(w.c.writeBuf) { - err = w.c.flushFrame(false, nil) + if w.pos == len(w.c.writeBuf) { + err = w.flushFrame(false, nil) if err != nil { break } } var n int - n, err = r.Read(w.c.writeBuf[w.c.writePos:]) - w.c.writePos += n + n, err = r.Read(w.c.writeBuf[w.pos:]) + w.pos += n nn += int64(n) if err != nil { if err == io.EOF { @@ -601,27 +693,59 @@ func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) { } func (w *messageWriter) Close() error { - if err := w.err(); err != nil { + if w.err != nil { + return w.err + } + if err := w.flushFrame(true, nil); err != nil { return err } - return w.c.flushFrame(true, nil) + w.err = errWriteClosed + return nil +} + +// WritePreparedMessage writes prepared message into connection. +func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error { + frameType, frameData, err := pm.frame(prepareKey{ + isServer: c.isServer, + compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType), + compressionLevel: c.compressionLevel, + }) + if err != nil { + return err + } + if c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = true + err = c.write(frameType, c.writeDeadline, frameData, nil) + if !c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = false + return err } // WriteMessage is a helper method for getting a writer using NextWriter, // writing the message and closing the writer. func (c *Conn) WriteMessage(messageType int, data []byte) error { + + if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { + // Fast path with no allocations and single frame. + + if err := c.prepWrite(messageType); err != nil { + return err + } + mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize} + n := copy(c.writeBuf[mw.pos:], data) + mw.pos += n + data = data[n:] + return mw.flushFrame(true, data) + } + w, err := c.NextWriter(messageType) if err != nil { return err } - if _, ok := w.(*messageWriter); ok && c.isServer { - // Optimize write as a single frame. - n := copy(c.writeBuf[c.writePos:], data) - c.writePos += n - data = data[n:] - err = c.flushFrame(true, data) - return err - } if _, err = w.Write(data); err != nil { return err } @@ -658,12 +782,17 @@ func (c *Conn) advanceFrame() (int, error) { final := p[0]&finalBit != 0 frameType := int(p[0] & 0xf) - reserved := int((p[0] >> 4) & 0x7) mask := p[1]&maskBit != 0 c.readRemaining = int64(p[1] & 0x7f) - if reserved != 0 { - return noFrame, c.handleProtocolError("unexpected reserved bits " + strconv.Itoa(reserved)) + c.readDecompress = false + if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 { + c.readDecompress = true + p[0] &^= rsv1Bit + } + + if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 { + return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16)) } switch frameType { @@ -759,11 +888,9 @@ func (c *Conn) advanceFrame() (int, error) { return noFrame, err } case CloseMessage: - echoMessage := []byte{} closeCode := CloseNoStatusReceived closeText := "" if len(payload) >= 2 { - echoMessage = payload[:2] closeCode = int(binary.BigEndian.Uint16(payload)) if !isValidReceivedCloseCode(closeCode) { return noFrame, c.handleProtocolError("invalid close code") @@ -773,7 +900,9 @@ func (c *Conn) advanceFrame() (int, error) { return noFrame, c.handleProtocolError("invalid utf8 payload in close frame") } } - c.WriteControl(CloseMessage, echoMessage, time.Now().Add(writeWait)) + if err := c.handleClose(closeCode, closeText); err != nil { + return noFrame, err + } return noFrame, &CloseError{Code: closeCode, Text: closeText} } @@ -796,6 +925,11 @@ func (c *Conn) handleProtocolError(message string) error { // permanent. Once this method returns a non-nil error, all subsequent calls to // this method return the same error. func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { + // Close previous reader, only relevant for decompression. + if c.reader != nil { + c.reader.Close() + c.reader = nil + } c.messageReader = nil c.readLength = 0 @@ -807,9 +941,12 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { break } if frameType == TextMessage || frameType == BinaryMessage { - r := &messageReader{c} - c.messageReader = r - return frameType, r, nil + c.messageReader = &messageReader{c} + c.reader = c.messageReader + if c.readDecompress { + c.reader = c.newDecompressionReader(c.reader) + } + return frameType, c.reader, nil } } @@ -871,6 +1008,10 @@ func (r *messageReader) Read(b []byte) (int, error) { return 0, err } +func (r *messageReader) Close() error { + return nil +} + // ReadMessage is a helper method for getting a reader using NextReader and // reading from that reader to a buffer. func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { @@ -898,6 +1039,38 @@ func (c *Conn) SetReadLimit(limit int64) { c.readLimit = limit } +// CloseHandler returns the current close handler +func (c *Conn) CloseHandler() func(code int, text string) error { + return c.handleClose +} + +// SetCloseHandler sets the handler for close messages received from the peer. +// The code argument to h is the received close code or CloseNoStatusReceived +// if the close message is empty. The default close handler sends a close frame +// back to the peer. +// +// The application must read the connection to process close messages as +// described in the section on Control Frames above. +// +// The connection read methods return a CloseError when a close frame is +// received. Most applications should handle close messages as part of their +// normal error handling. Applications should only set a close handler when the +// application must perform some action before sending a close frame back to +// the peer. +func (c *Conn) SetCloseHandler(h func(code int, text string) error) { + if h == nil { + h = func(code int, text string) error { + message := []byte{} + if code != CloseNoStatusReceived { + message = FormatCloseMessage(code, "") + } + c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) + return nil + } + } + c.handleClose = h +} + // PingHandler returns the current ping handler func (c *Conn) PingHandler() func(appData string) error { return c.handlePing @@ -906,6 +1079,9 @@ func (c *Conn) PingHandler() func(appData string) error { // SetPingHandler sets the handler for ping messages received from the peer. // The appData argument to h is the PING frame application data. The default // ping handler sends a pong to the peer. +// +// The application must read the connection to process ping messages as +// described in the section on Control Frames above. func (c *Conn) SetPingHandler(h func(appData string) error) { if h == nil { h = func(message string) error { @@ -929,6 +1105,9 @@ func (c *Conn) PongHandler() func(appData string) error { // SetPongHandler sets the handler for pong messages received from the peer. // The appData argument to h is the PONG frame application data. The default // pong handler does nothing. +// +// The application must read the connection to process ping messages as +// described in the section on Control Frames above. func (c *Conn) SetPongHandler(h func(appData string) error) { if h == nil { h = func(string) error { return nil } @@ -942,6 +1121,25 @@ func (c *Conn) UnderlyingConn() net.Conn { return c.conn } +// EnableWriteCompression enables and disables write compression of +// subsequent text and binary messages. This function is a noop if +// compression was not negotiated with the peer. +func (c *Conn) EnableWriteCompression(enable bool) { + c.enableWriteCompression = enable +} + +// SetCompressionLevel sets the flate compression level for subsequent text and +// binary messages. This function is a noop if compression was not negotiated +// with the peer. See the compress/flate package for a description of +// compression levels. +func (c *Conn) SetCompressionLevel(level int) error { + if !isValidCompressionLevel(level) { + return errors.New("websocket: invalid compression level") + } + c.compressionLevel = level + return nil +} + // FormatCloseMessage formats closeCode and text as a WebSocket close message. func FormatCloseMessage(closeCode int, text string) []byte { buf := make([]byte, 2+len(text)) diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go index c901a7a..e291a95 100644 --- a/vendor/github.com/gorilla/websocket/doc.go +++ b/vendor/github.com/gorilla/websocket/doc.go @@ -118,9 +118,10 @@ // // Applications are responsible for ensuring that no more than one goroutine // calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, -// WriteJSON) concurrently and that no more than one goroutine calls the read -// methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, -// SetPingHandler) concurrently. +// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and +// that no more than one goroutine calls the read methods (NextReader, +// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) +// concurrently. // // The Close and WriteControl methods can be called concurrently with all other // methods. @@ -149,4 +150,31 @@ // The deprecated Upgrade function does not enforce an origin policy. It's the // application's responsibility to check the Origin header before calling // Upgrade. +// +// Compression EXPERIMENTAL +// +// Per message compression extensions (RFC 7692) are experimentally supported +// by this package in a limited capacity. Setting the EnableCompression option +// to true in Dialer or Upgrader will attempt to negotiate per message deflate +// support. +// +// var upgrader = websocket.Upgrader{ +// EnableCompression: true, +// } +// +// If compression was successfully negotiated with the connection's peer, any +// message received in compressed form will be automatically decompressed. +// All Read methods will return uncompressed bytes. +// +// Per message compression of messages written to a connection can be enabled +// or disabled by calling the corresponding Conn method: +// +// conn.EnableWriteCompression(false) +// +// Currently this package does not support compression with "context takeover". +// This means that messages must be compressed and decompressed in isolation, +// without retaining sliding window or dictionary state across messages. For +// more details refer to RFC 7692. +// +// Use of compression is experimental and may result in decreased performance. package websocket diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go new file mode 100644 index 0000000..6a88bbc --- /dev/null +++ b/vendor/github.com/gorilla/websocket/mask.go @@ -0,0 +1,55 @@ +// Copyright 2016 The Gorilla WebSocket 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 !appengine + +package websocket + +import "unsafe" + +const wordSize = int(unsafe.Sizeof(uintptr(0))) + +func maskBytes(key [4]byte, pos int, b []byte) int { + + // Mask one byte at a time for small buffers. + if len(b) < 2*wordSize { + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + return pos & 3 + } + + // Mask one byte at a time to word boundary. + if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 { + n = wordSize - n + for i := range b[:n] { + b[i] ^= key[pos&3] + pos++ + } + b = b[n:] + } + + // Create aligned word size key. + var k [wordSize]byte + for i := range k { + k[i] = key[(pos+i)&3] + } + kw := *(*uintptr)(unsafe.Pointer(&k)) + + // Mask one word at a time. + n := (len(b) / wordSize) * wordSize + for i := 0; i < n; i += wordSize { + *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw + } + + // Mask one byte at a time for remaining bytes. + b = b[n:] + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + + return pos & 3 +} diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go new file mode 100644 index 0000000..2aac060 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/mask_safe.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Gorilla WebSocket 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 appengine + +package websocket + +func maskBytes(key [4]byte, pos int, b []byte) int { + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + return pos & 3 +} diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go new file mode 100644 index 0000000..1efffbd --- /dev/null +++ b/vendor/github.com/gorilla/websocket/prepared.go @@ -0,0 +1,103 @@ +// Copyright 2017 The Gorilla WebSocket 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 websocket + +import ( + "bytes" + "net" + "sync" + "time" +) + +// PreparedMessage caches on the wire representations of a message payload. +// Use PreparedMessage to efficiently send a message payload to multiple +// connections. PreparedMessage is especially useful when compression is used +// because the CPU and memory expensive compression operation can be executed +// once for a given set of compression options. +type PreparedMessage struct { + messageType int + data []byte + err error + mu sync.Mutex + frames map[prepareKey]*preparedFrame +} + +// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage. +type prepareKey struct { + isServer bool + compress bool + compressionLevel int +} + +// preparedFrame contains data in wire representation. +type preparedFrame struct { + once sync.Once + data []byte +} + +// NewPreparedMessage returns an initialized PreparedMessage. You can then send +// it to connection using WritePreparedMessage method. Valid wire +// representation will be calculated lazily only once for a set of current +// connection options. +func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) { + pm := &PreparedMessage{ + messageType: messageType, + frames: make(map[prepareKey]*preparedFrame), + data: data, + } + + // Prepare a plain server frame. + _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false}) + if err != nil { + return nil, err + } + + // To protect against caller modifying the data argument, remember the data + // copied to the plain server frame. + pm.data = frameData[len(frameData)-len(data):] + return pm, nil +} + +func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { + pm.mu.Lock() + frame, ok := pm.frames[key] + if !ok { + frame = &preparedFrame{} + pm.frames[key] = frame + } + pm.mu.Unlock() + + var err error + frame.once.Do(func() { + // Prepare a frame using a 'fake' connection. + // TODO: Refactor code in conn.go to allow more direct construction of + // the frame. + mu := make(chan bool, 1) + mu <- true + var nc prepareConn + c := &Conn{ + conn: &nc, + mu: mu, + isServer: key.isServer, + compressionLevel: key.compressionLevel, + enableWriteCompression: true, + writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize), + } + if key.compress { + c.newCompressionWriter = compressNoContextTakeover + } + err = c.WriteMessage(pm.messageType, pm.data) + frame.data = nc.buf.Bytes() + }) + return pm.messageType, frame.data, err +} + +type prepareConn struct { + buf bytes.Buffer + net.Conn +} + +func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) } +func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil } diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go index 8d7137d..3495e0f 100644 --- a/vendor/github.com/gorilla/websocket/server.go +++ b/vendor/github.com/gorilla/websocket/server.go @@ -28,8 +28,9 @@ type Upgrader struct { HandshakeTimeout time.Duration // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer - // size is zero, then a default value of 4096 is used. The I/O buffer sizes - // do not limit the size of the messages that can be sent or received. + // size is zero, then buffers allocated by the HTTP server are used. The + // I/O buffer sizes do not limit the size of the messages that can be sent + // or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the server's supported protocols in order of @@ -46,6 +47,12 @@ type Upgrader struct { // CheckOrigin is nil, the host in the Origin header must not be set or // must match the host of the request. CheckOrigin func(r *http.Request) bool + + // EnableCompression specify if the server should attempt to negotiate per + // message compression (RFC 7692). Setting this value to true does not + // guarantee that compression will be supported. Currently only "no context + // takeover" modes are supported. + EnableCompression bool } func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) { @@ -53,6 +60,7 @@ func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status in if u.Error != nil { u.Error(w, r, status, err) } else { + w.Header().Set("Sec-Websocket-Version", "13") http.Error(w, http.StatusText(status), status) } return nil, err @@ -97,18 +105,23 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header // response. func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { if r.Method != "GET" { - return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET") + return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET") } - if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" { - return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") + + if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { + return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported") } if !tokenListContainsValue(r.Header, "Connection", "upgrade") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header") } if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header") + } + + if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { + return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") } checkOrigin := u.CheckOrigin @@ -116,19 +129,30 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade checkOrigin = checkSameOrigin } if !checkOrigin(r) { - return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") + return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed") } challengeKey := r.Header.Get("Sec-Websocket-Key") if challengeKey == "" { - return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank") } subprotocol := u.selectSubprotocol(r, responseHeader) + // Negotiate PMCE + var compress bool + if u.EnableCompression { + for _, ext := range parseExtensions(r.Header) { + if ext[""] != "permessage-deflate" { + continue + } + compress = true + break + } + } + var ( netConn net.Conn - br *bufio.Reader err error ) @@ -136,21 +160,25 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade if !ok { return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") } - var rw *bufio.ReadWriter - netConn, rw, err = h.Hijack() + var brw *bufio.ReadWriter + netConn, brw, err = h.Hijack() if err != nil { return u.returnError(w, r, http.StatusInternalServerError, err.Error()) } - br = rw.Reader - if br.Buffered() > 0 { + if brw.Reader.Buffered() > 0 { netConn.Close() return nil, errors.New("websocket: client sent data before handshake is complete") } - c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize) + c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw) c.subprotocol = subprotocol + if compress { + c.newCompressionWriter = compressNoContextTakeover + c.newDecompressionReader = decompressNoContextTakeover + } + p := c.writeBuf[:0] p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) p = append(p, computeAcceptKey(challengeKey)...) @@ -160,6 +188,9 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade p = append(p, c.subprotocol...) p = append(p, "\r\n"...) } + if compress { + p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...) + } for k, vs := range responseHeader { if k == "Sec-Websocket-Protocol" { continue diff --git a/vendor/github.com/howeyc/fsnotify/AUTHORS b/vendor/github.com/howeyc/fsnotify/AUTHORS deleted file mode 100644 index e52b72f..0000000 --- a/vendor/github.com/howeyc/fsnotify/AUTHORS +++ /dev/null @@ -1,28 +0,0 @@ -# Names should be added to this file as -# Name or Organization -# The email address is not required for organizations. - -# You can update this list using the following command: -# -# $ git shortlog -se | awk '{print $2 " " $3 " " $4}' - -# Please keep the list sorted. - -Adrien Bustany -Caleb Spare -Case Nelson -Chris Howey -Christoffer Buchholz -Dave Cheney -Francisco Souza -John C Barstow -Kelvin Fo -Nathan Youngman -Paul Hammond -Pursuit92 -Rob Figueiredo -Travis Cline -Tudor Golubenco -bronze1man -debrando -henrikedwards diff --git a/vendor/github.com/howeyc/fsnotify/CHANGELOG.md b/vendor/github.com/howeyc/fsnotify/CHANGELOG.md deleted file mode 100644 index 761686a..0000000 --- a/vendor/github.com/howeyc/fsnotify/CHANGELOG.md +++ /dev/null @@ -1,160 +0,0 @@ -# Changelog - -## v0.9.0 / 2014-01-17 - -* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) -* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) -* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. - -## v0.8.12 / 2013-11-13 - -* [API] Remove FD_SET and friends from Linux adapter - -## v0.8.11 / 2013-11-02 - -* [Doc] Add Changelog [#72][] (thanks @nathany) -* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond) - -## v0.8.10 / 2013-10-19 - -* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) -* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) -* [Doc] specify OS-specific limits in README (thanks @debrando) - -## v0.8.9 / 2013-09-08 - -* [Doc] Contributing (thanks @nathany) -* [Doc] update package path in example code [#63][] (thanks @paulhammond) -* [Doc] GoCI badge in README (Linux only) [#60][] -* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) - -## v0.8.8 / 2013-06-17 - -* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) - -## v0.8.7 / 2013-06-03 - -* [API] Make syscall flags internal -* [Fix] inotify: ignore event changes -* [Fix] race in symlink test [#45][] (reported by @srid) -* [Fix] tests on Windows -* lower case error messages - -## v0.8.6 / 2013-05-23 - -* kqueue: Use EVT_ONLY flag on Darwin -* [Doc] Update README with full example - -## v0.8.5 / 2013-05-09 - -* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) - -## v0.8.4 / 2013-04-07 - -* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) - -## v0.8.3 / 2013-03-13 - -* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) -* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) - -## v0.8.2 / 2013-02-07 - -* [Doc] add Authors -* [Fix] fix data races for map access [#29][] (thanks @fsouza) - -## v0.8.1 / 2013-01-09 - -* [Fix] Windows path separators -* [Doc] BSD License - -## v0.8.0 / 2012-11-09 - -* kqueue: directory watching improvements (thanks @vmirage) -* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) -* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) - -## v0.7.4 / 2012-10-09 - -* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) -* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) -* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) -* [Fix] kqueue: modify after recreation of file - -## v0.7.3 / 2012-09-27 - -* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) -* [Fix] kqueue: no longer get duplicate CREATE events - -## v0.7.2 / 2012-09-01 - -* kqueue: events for created directories - -## v0.7.1 / 2012-07-14 - -* [Fix] for renaming files - -## v0.7.0 / 2012-07-02 - -* [Feature] FSNotify flags -* [Fix] inotify: Added file name back to event path - -## v0.6.0 / 2012-06-06 - -* kqueue: watch files after directory created (thanks @tmc) - -## v0.5.1 / 2012-05-22 - -* [Fix] inotify: remove all watches before Close() - -## v0.5.0 / 2012-05-03 - -* [API] kqueue: return errors during watch instead of sending over channel -* kqueue: match symlink behavior on Linux -* inotify: add `DELETE_SELF` (requested by @taralx) -* [Fix] kqueue: handle EINTR (reported by @robfig) -* [Doc] Godoc example [#1][] (thanks @davecheney) - -## v0.4.0 / 2012-03-30 - -* Go 1 released: build with go tool -* [Feature] Windows support using winfsnotify -* Windows does not have attribute change notifications -* Roll attribute notifications into IsModify - -## v0.3.0 / 2012-02-19 - -* kqueue: add files when watch directory - -## v0.2.0 / 2011-12-30 - -* update to latest Go weekly code - -## v0.1.0 / 2011-10-19 - -* kqueue: add watch on file creation to match inotify -* kqueue: create file event -* inotify: ignore `IN_IGNORED` events -* event String() -* linux: common FileEvent functions -* initial commit - -[#79]: https://github.com/howeyc/fsnotify/pull/79 -[#77]: https://github.com/howeyc/fsnotify/pull/77 -[#72]: https://github.com/howeyc/fsnotify/issues/72 -[#71]: https://github.com/howeyc/fsnotify/issues/71 -[#70]: https://github.com/howeyc/fsnotify/issues/70 -[#63]: https://github.com/howeyc/fsnotify/issues/63 -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#60]: https://github.com/howeyc/fsnotify/issues/60 -[#59]: https://github.com/howeyc/fsnotify/issues/59 -[#49]: https://github.com/howeyc/fsnotify/issues/49 -[#45]: https://github.com/howeyc/fsnotify/issues/45 -[#40]: https://github.com/howeyc/fsnotify/issues/40 -[#36]: https://github.com/howeyc/fsnotify/issues/36 -[#33]: https://github.com/howeyc/fsnotify/issues/33 -[#29]: https://github.com/howeyc/fsnotify/issues/29 -[#25]: https://github.com/howeyc/fsnotify/issues/25 -[#24]: https://github.com/howeyc/fsnotify/issues/24 -[#21]: https://github.com/howeyc/fsnotify/issues/21 -[#1]: https://github.com/howeyc/fsnotify/issues/1 diff --git a/vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md b/vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md deleted file mode 100644 index b2025d7..0000000 --- a/vendor/github.com/howeyc/fsnotify/CONTRIBUTING.md +++ /dev/null @@ -1,7 +0,0 @@ -# Contributing - -## Moving Notice - -There is a fork being actively developed with a new API in preparation for the Go Standard Library: -[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify) - diff --git a/vendor/github.com/howeyc/fsnotify/README.md b/vendor/github.com/howeyc/fsnotify/README.md deleted file mode 100644 index 7fdaf7c..0000000 --- a/vendor/github.com/howeyc/fsnotify/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# File system notifications for Go - -[![GoDoc](https://godoc.org/github.com/howeyc/fsnotify?status.png)](http://godoc.org/github.com/howeyc/fsnotify) - -Cross platform: Windows, Linux, BSD and OS X. - -## Moving Notice - -There is a fork being actively developed with a new API in preparation for the Go Standard Library: -[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify) - -## Example: - -```go -package main - -import ( - "log" - - "github.com/howeyc/fsnotify" -) - -func main() { - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Fatal(err) - } - - done := make(chan bool) - - // Process events - go func() { - for { - select { - case ev := <-watcher.Event: - log.Println("event:", ev) - case err := <-watcher.Error: - log.Println("error:", err) - } - } - }() - - err = watcher.Watch("testDir") - if err != nil { - log.Fatal(err) - } - - // Hang so program doesn't exit - <-done - - /* ... do stuff ... */ - watcher.Close() -} -``` - -For each event: -* Name -* IsCreate() -* IsDelete() -* IsModify() -* IsRename() - -## FAQ - -**When a file is moved to another directory is it still being watched?** - -No (it shouldn't be, unless you are watching where it was moved to). - -**When I watch a directory, are all subdirectories watched as well?** - -No, you must add watches for any directory you want to watch (a recursive watcher is in the works [#56][]). - -**Do I have to watch the Error and Event channels in a separate goroutine?** - -As of now, yes. Looking into making this single-thread friendly (see [#7][]) - -**Why am I receiving multiple events for the same file on OS X?** - -Spotlight indexing on OS X can result in multiple events (see [#62][]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#54][]). - -**How many files can be watched at once?** - -There are OS-specific limits as to how many watches can be created: -* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, -reaching this limit results in a "no space left on device" error. -* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. - - -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#56]: https://github.com/howeyc/fsnotify/issues/56 -[#54]: https://github.com/howeyc/fsnotify/issues/54 -[#7]: https://github.com/howeyc/fsnotify/issues/7 - diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify.go b/vendor/github.com/howeyc/fsnotify/fsnotify.go deleted file mode 100644 index 9a48d84..0000000 --- a/vendor/github.com/howeyc/fsnotify/fsnotify.go +++ /dev/null @@ -1,111 +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 fsnotify implements file system notification. -package fsnotify - -import "fmt" - -const ( - FSN_CREATE = 1 - FSN_MODIFY = 2 - FSN_DELETE = 4 - FSN_RENAME = 8 - - FSN_ALL = FSN_MODIFY | FSN_DELETE | FSN_RENAME | FSN_CREATE -) - -// Purge events from interal chan to external chan if passes filter -func (w *Watcher) purgeEvents() { - for ev := range w.internalEvent { - sendEvent := false - w.fsnmut.Lock() - fsnFlags := w.fsnFlags[ev.Name] - w.fsnmut.Unlock() - - if (fsnFlags&FSN_CREATE == FSN_CREATE) && ev.IsCreate() { - sendEvent = true - } - - if (fsnFlags&FSN_MODIFY == FSN_MODIFY) && ev.IsModify() { - sendEvent = true - } - - if (fsnFlags&FSN_DELETE == FSN_DELETE) && ev.IsDelete() { - sendEvent = true - } - - if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() { - sendEvent = true - } - - if sendEvent { - w.Event <- ev - } - - // If there's no file, then no more events for user - // BSD must keep watch for internal use (watches DELETEs to keep track - // what files exist for create events) - if ev.IsDelete() { - w.fsnmut.Lock() - delete(w.fsnFlags, ev.Name) - w.fsnmut.Unlock() - } - } - - close(w.Event) -} - -// Watch a given file path -func (w *Watcher) Watch(path string) error { - return w.WatchFlags(path, FSN_ALL) -} - -// Watch a given file path for a particular set of notifications (FSN_MODIFY etc.) -func (w *Watcher) WatchFlags(path string, flags uint32) error { - w.fsnmut.Lock() - w.fsnFlags[path] = flags - w.fsnmut.Unlock() - return w.watch(path) -} - -// Remove a watch on a file -func (w *Watcher) RemoveWatch(path string) error { - w.fsnmut.Lock() - delete(w.fsnFlags, path) - w.fsnmut.Unlock() - return w.removeWatch(path) -} - -// String formats the event e in the form -// "filename: DELETE|MODIFY|..." -func (e *FileEvent) String() string { - var events string = "" - - if e.IsCreate() { - events += "|" + "CREATE" - } - - if e.IsDelete() { - events += "|" + "DELETE" - } - - if e.IsModify() { - events += "|" + "MODIFY" - } - - if e.IsRename() { - events += "|" + "RENAME" - } - - if e.IsAttrib() { - events += "|" + "ATTRIB" - } - - if len(events) > 0 { - events = events[1:] - } - - return fmt.Sprintf("%q: %s", e.Name, events) -} diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go b/vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go deleted file mode 100644 index 40c8476..0000000 --- a/vendor/github.com/howeyc/fsnotify/fsnotify_bsd.go +++ /dev/null @@ -1,496 +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. - -// +build freebsd openbsd netbsd dragonfly darwin - -package fsnotify - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sync" - "syscall" -) - -const ( - // Flags (from ) - sys_NOTE_DELETE = 0x0001 /* vnode was removed */ - sys_NOTE_WRITE = 0x0002 /* data contents changed */ - sys_NOTE_EXTEND = 0x0004 /* size increased */ - sys_NOTE_ATTRIB = 0x0008 /* attributes changed */ - sys_NOTE_LINK = 0x0010 /* link count changed */ - sys_NOTE_RENAME = 0x0020 /* vnode was renamed */ - sys_NOTE_REVOKE = 0x0040 /* vnode access was revoked */ - - // Watch all events - sys_NOTE_ALLEVENTS = sys_NOTE_DELETE | sys_NOTE_WRITE | sys_NOTE_ATTRIB | sys_NOTE_RENAME - - // Block for 100 ms on each call to kevent - keventWaitTime = 100e6 -) - -type FileEvent struct { - mask uint32 // Mask of events - Name string // File name (optional) - create bool // set by fsnotify package if found new file -} - -// IsCreate reports whether the FileEvent was triggered by a creation -func (e *FileEvent) IsCreate() bool { return e.create } - -// IsDelete reports whether the FileEvent was triggered by a delete -func (e *FileEvent) IsDelete() bool { return (e.mask & sys_NOTE_DELETE) == sys_NOTE_DELETE } - -// IsModify reports whether the FileEvent was triggered by a file modification -func (e *FileEvent) IsModify() bool { - return ((e.mask&sys_NOTE_WRITE) == sys_NOTE_WRITE || (e.mask&sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB) -} - -// IsRename reports whether the FileEvent was triggered by a change name -func (e *FileEvent) IsRename() bool { return (e.mask & sys_NOTE_RENAME) == sys_NOTE_RENAME } - -// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata. -func (e *FileEvent) IsAttrib() bool { - return (e.mask & sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB -} - -type Watcher struct { - mu sync.Mutex // Mutex for the Watcher itself. - kq int // File descriptor (as returned by the kqueue() syscall) - watches map[string]int // Map of watched file descriptors (key: path) - wmut sync.Mutex // Protects access to watches. - fsnFlags map[string]uint32 // Map of watched files to flags used for filter - fsnmut sync.Mutex // Protects access to fsnFlags. - enFlags map[string]uint32 // Map of watched files to evfilt note flags used in kqueue - enmut sync.Mutex // Protects access to enFlags. - paths map[int]string // Map of watched paths (key: watch descriptor) - finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor) - pmut sync.Mutex // Protects access to paths and finfo. - fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events) - femut sync.Mutex // Protects access to fileExists. - externalWatches map[string]bool // Map of watches added by user of the library. - ewmut sync.Mutex // Protects access to externalWatches. - Error chan error // Errors are sent on this channel - internalEvent chan *FileEvent // Events are queued on this channel - Event chan *FileEvent // Events are returned on this channel - done chan bool // Channel for sending a "quit message" to the reader goroutine - isClosed bool // Set to true when Close() is first called -} - -// NewWatcher creates and returns a new kevent instance using kqueue(2) -func NewWatcher() (*Watcher, error) { - fd, errno := syscall.Kqueue() - if fd == -1 { - return nil, os.NewSyscallError("kqueue", errno) - } - w := &Watcher{ - kq: fd, - watches: make(map[string]int), - fsnFlags: make(map[string]uint32), - enFlags: make(map[string]uint32), - paths: make(map[int]string), - finfo: make(map[int]os.FileInfo), - fileExists: make(map[string]bool), - externalWatches: make(map[string]bool), - internalEvent: make(chan *FileEvent), - Event: make(chan *FileEvent), - Error: make(chan error), - done: make(chan bool, 1), - } - - go w.readEvents() - go w.purgeEvents() - return w, nil -} - -// Close closes a kevent watcher instance -// It sends a message to the reader goroutine to quit and removes all watches -// associated with the kevent instance -func (w *Watcher) Close() error { - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return nil - } - w.isClosed = true - w.mu.Unlock() - - // Send "quit" message to the reader goroutine - w.done <- true - w.wmut.Lock() - ws := w.watches - w.wmut.Unlock() - for path := range ws { - w.removeWatch(path) - } - - return nil -} - -// AddWatch adds path to the watched file set. -// The flags are interpreted as described in kevent(2). -func (w *Watcher) addWatch(path string, flags uint32) error { - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return errors.New("kevent instance already closed") - } - w.mu.Unlock() - - watchDir := false - - w.wmut.Lock() - watchfd, found := w.watches[path] - w.wmut.Unlock() - if !found { - fi, errstat := os.Lstat(path) - if errstat != nil { - return errstat - } - - // don't watch socket - if fi.Mode()&os.ModeSocket == os.ModeSocket { - return nil - } - - // Follow Symlinks - // Unfortunately, Linux can add bogus symlinks to watch list without - // issue, and Windows can't do symlinks period (AFAIK). To maintain - // consistency, we will act like everything is fine. There will simply - // be no file events for broken symlinks. - // Hence the returns of nil on errors. - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { - path, err := filepath.EvalSymlinks(path) - if err != nil { - return nil - } - - fi, errstat = os.Lstat(path) - if errstat != nil { - return nil - } - } - - fd, errno := syscall.Open(path, open_FLAGS, 0700) - if fd == -1 { - return errno - } - watchfd = fd - - w.wmut.Lock() - w.watches[path] = watchfd - w.wmut.Unlock() - - w.pmut.Lock() - w.paths[watchfd] = path - w.finfo[watchfd] = fi - w.pmut.Unlock() - } - // Watch the directory if it has not been watched before. - w.pmut.Lock() - w.enmut.Lock() - if w.finfo[watchfd].IsDir() && - (flags&sys_NOTE_WRITE) == sys_NOTE_WRITE && - (!found || (w.enFlags[path]&sys_NOTE_WRITE) != sys_NOTE_WRITE) { - watchDir = true - } - w.enmut.Unlock() - w.pmut.Unlock() - - w.enmut.Lock() - w.enFlags[path] = flags - w.enmut.Unlock() - - var kbuf [1]syscall.Kevent_t - watchEntry := &kbuf[0] - watchEntry.Fflags = flags - syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR) - entryFlags := watchEntry.Flags - success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil) - if success == -1 { - return errno - } else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR { - return errors.New("kevent add error") - } - - if watchDir { - errdir := w.watchDirectoryFiles(path) - if errdir != nil { - return errdir - } - } - return nil -} - -// Watch adds path to the watched file set, watching all events. -func (w *Watcher) watch(path string) error { - w.ewmut.Lock() - w.externalWatches[path] = true - w.ewmut.Unlock() - return w.addWatch(path, sys_NOTE_ALLEVENTS) -} - -// RemoveWatch removes path from the watched file set. -func (w *Watcher) removeWatch(path string) error { - w.wmut.Lock() - watchfd, ok := w.watches[path] - w.wmut.Unlock() - if !ok { - return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path)) - } - var kbuf [1]syscall.Kevent_t - watchEntry := &kbuf[0] - syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE) - entryFlags := watchEntry.Flags - success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil) - if success == -1 { - return os.NewSyscallError("kevent_rm_watch", errno) - } else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR { - return errors.New("kevent rm error") - } - syscall.Close(watchfd) - w.wmut.Lock() - delete(w.watches, path) - w.wmut.Unlock() - w.enmut.Lock() - delete(w.enFlags, path) - w.enmut.Unlock() - w.pmut.Lock() - delete(w.paths, watchfd) - fInfo := w.finfo[watchfd] - delete(w.finfo, watchfd) - w.pmut.Unlock() - - // Find all watched paths that are in this directory that are not external. - if fInfo.IsDir() { - var pathsToRemove []string - w.pmut.Lock() - for _, wpath := range w.paths { - wdir, _ := filepath.Split(wpath) - if filepath.Clean(wdir) == filepath.Clean(path) { - w.ewmut.Lock() - if !w.externalWatches[wpath] { - pathsToRemove = append(pathsToRemove, wpath) - } - w.ewmut.Unlock() - } - } - w.pmut.Unlock() - for _, p := range pathsToRemove { - // Since these are internal, not much sense in propagating error - // to the user, as that will just confuse them with an error about - // a path they did not explicitly watch themselves. - w.removeWatch(p) - } - } - - return nil -} - -// readEvents reads from the kqueue file descriptor, converts the -// received events into Event objects and sends them via the Event channel -func (w *Watcher) readEvents() { - var ( - eventbuf [10]syscall.Kevent_t // Event buffer - events []syscall.Kevent_t // Received events - twait *syscall.Timespec // Time to block waiting for events - n int // Number of events returned from kevent - errno error // Syscall errno - ) - events = eventbuf[0:0] - twait = new(syscall.Timespec) - *twait = syscall.NsecToTimespec(keventWaitTime) - - for { - // See if there is a message on the "done" channel - var done bool - select { - case done = <-w.done: - default: - } - - // If "done" message is received - if done { - errno := syscall.Close(w.kq) - if errno != nil { - w.Error <- os.NewSyscallError("close", errno) - } - close(w.internalEvent) - close(w.Error) - return - } - - // Get new events - if len(events) == 0 { - n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait) - - // EINTR is okay, basically the syscall was interrupted before - // timeout expired. - if errno != nil && errno != syscall.EINTR { - w.Error <- os.NewSyscallError("kevent", errno) - continue - } - - // Received some events - if n > 0 { - events = eventbuf[0:n] - } - } - - // Flush the events we received to the events channel - for len(events) > 0 { - fileEvent := new(FileEvent) - watchEvent := &events[0] - fileEvent.mask = uint32(watchEvent.Fflags) - w.pmut.Lock() - fileEvent.Name = w.paths[int(watchEvent.Ident)] - fileInfo := w.finfo[int(watchEvent.Ident)] - w.pmut.Unlock() - if fileInfo != nil && fileInfo.IsDir() && !fileEvent.IsDelete() { - // Double check to make sure the directory exist. This can happen when - // we do a rm -fr on a recursively watched folders and we receive a - // modification event first but the folder has been deleted and later - // receive the delete event - if _, err := os.Lstat(fileEvent.Name); os.IsNotExist(err) { - // mark is as delete event - fileEvent.mask |= sys_NOTE_DELETE - } - } - - if fileInfo != nil && fileInfo.IsDir() && fileEvent.IsModify() && !fileEvent.IsDelete() { - w.sendDirectoryChangeEvents(fileEvent.Name) - } else { - // Send the event on the events channel - w.internalEvent <- fileEvent - } - - // Move to next event - events = events[1:] - - if fileEvent.IsRename() { - w.removeWatch(fileEvent.Name) - w.femut.Lock() - delete(w.fileExists, fileEvent.Name) - w.femut.Unlock() - } - if fileEvent.IsDelete() { - w.removeWatch(fileEvent.Name) - w.femut.Lock() - delete(w.fileExists, fileEvent.Name) - w.femut.Unlock() - - // Look for a file that may have overwritten this - // (ie mv f1 f2 will delete f2 then create f2) - fileDir, _ := filepath.Split(fileEvent.Name) - fileDir = filepath.Clean(fileDir) - w.wmut.Lock() - _, found := w.watches[fileDir] - w.wmut.Unlock() - if found { - // make sure the directory exist before we watch for changes. When we - // do a recursive watch and perform rm -fr, the parent directory might - // have gone missing, ignore the missing directory and let the - // upcoming delete event remove the watch form the parent folder - if _, err := os.Lstat(fileDir); !os.IsNotExist(err) { - w.sendDirectoryChangeEvents(fileDir) - } - } - } - } - } -} - -func (w *Watcher) watchDirectoryFiles(dirPath string) error { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - return err - } - - // Search for new files - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - - // Inherit fsnFlags from parent directory - w.fsnmut.Lock() - if flags, found := w.fsnFlags[dirPath]; found { - w.fsnFlags[filePath] = flags - } else { - w.fsnFlags[filePath] = FSN_ALL - } - w.fsnmut.Unlock() - - if fileInfo.IsDir() == false { - // Watch file to mimic linux fsnotify - e := w.addWatch(filePath, sys_NOTE_ALLEVENTS) - if e != nil { - return e - } - } else { - // If the user is currently watching directory - // we want to preserve the flags used - w.enmut.Lock() - currFlags, found := w.enFlags[filePath] - w.enmut.Unlock() - var newFlags uint32 = sys_NOTE_DELETE - if found { - newFlags |= currFlags - } - - // Linux gives deletes if not explicitly watching - e := w.addWatch(filePath, newFlags) - if e != nil { - return e - } - } - w.femut.Lock() - w.fileExists[filePath] = true - w.femut.Unlock() - } - - return nil -} - -// sendDirectoryEvents searches the directory for newly created files -// and sends them over the event channel. This functionality is to have -// the BSD version of fsnotify match linux fsnotify which provides a -// create event for files created in a watched directory. -func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - w.Error <- err - } - - // Search for new files - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - w.femut.Lock() - _, doesExist := w.fileExists[filePath] - w.femut.Unlock() - if !doesExist { - // Inherit fsnFlags from parent directory - w.fsnmut.Lock() - if flags, found := w.fsnFlags[dirPath]; found { - w.fsnFlags[filePath] = flags - } else { - w.fsnFlags[filePath] = FSN_ALL - } - w.fsnmut.Unlock() - - // Send create event - fileEvent := new(FileEvent) - fileEvent.Name = filePath - fileEvent.create = true - w.internalEvent <- fileEvent - } - w.femut.Lock() - w.fileExists[filePath] = true - w.femut.Unlock() - } - w.watchDirectoryFiles(dirPath) -} diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_linux.go b/vendor/github.com/howeyc/fsnotify/fsnotify_linux.go deleted file mode 100644 index 80ade87..0000000 --- a/vendor/github.com/howeyc/fsnotify/fsnotify_linux.go +++ /dev/null @@ -1,304 +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. - -// +build linux - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "strings" - "sync" - "syscall" - "unsafe" -) - -const ( - // Options for inotify_init() are not exported - // sys_IN_CLOEXEC uint32 = syscall.IN_CLOEXEC - // sys_IN_NONBLOCK uint32 = syscall.IN_NONBLOCK - - // Options for AddWatch - sys_IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW - sys_IN_ONESHOT uint32 = syscall.IN_ONESHOT - sys_IN_ONLYDIR uint32 = syscall.IN_ONLYDIR - - // The "sys_IN_MASK_ADD" option is not exported, as AddWatch - // adds it automatically, if there is already a watch for the given path - // sys_IN_MASK_ADD uint32 = syscall.IN_MASK_ADD - - // Events - sys_IN_ACCESS uint32 = syscall.IN_ACCESS - sys_IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS - sys_IN_ATTRIB uint32 = syscall.IN_ATTRIB - sys_IN_CLOSE uint32 = syscall.IN_CLOSE - sys_IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE - sys_IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE - sys_IN_CREATE uint32 = syscall.IN_CREATE - sys_IN_DELETE uint32 = syscall.IN_DELETE - sys_IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF - sys_IN_MODIFY uint32 = syscall.IN_MODIFY - sys_IN_MOVE uint32 = syscall.IN_MOVE - sys_IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM - sys_IN_MOVED_TO uint32 = syscall.IN_MOVED_TO - sys_IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF - sys_IN_OPEN uint32 = syscall.IN_OPEN - - sys_AGNOSTIC_EVENTS = sys_IN_MOVED_TO | sys_IN_MOVED_FROM | sys_IN_CREATE | sys_IN_ATTRIB | sys_IN_MODIFY | sys_IN_MOVE_SELF | sys_IN_DELETE | sys_IN_DELETE_SELF - - // Special events - sys_IN_ISDIR uint32 = syscall.IN_ISDIR - sys_IN_IGNORED uint32 = syscall.IN_IGNORED - sys_IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW - sys_IN_UNMOUNT uint32 = syscall.IN_UNMOUNT -) - -type FileEvent struct { - mask uint32 // Mask of events - cookie uint32 // Unique cookie associating related events (for rename(2)) - Name string // File name (optional) -} - -// IsCreate reports whether the FileEvent was triggered by a creation -func (e *FileEvent) IsCreate() bool { - return (e.mask&sys_IN_CREATE) == sys_IN_CREATE || (e.mask&sys_IN_MOVED_TO) == sys_IN_MOVED_TO -} - -// IsDelete reports whether the FileEvent was triggered by a delete -func (e *FileEvent) IsDelete() bool { - return (e.mask&sys_IN_DELETE_SELF) == sys_IN_DELETE_SELF || (e.mask&sys_IN_DELETE) == sys_IN_DELETE -} - -// IsModify reports whether the FileEvent was triggered by a file modification or attribute change -func (e *FileEvent) IsModify() bool { - return ((e.mask&sys_IN_MODIFY) == sys_IN_MODIFY || (e.mask&sys_IN_ATTRIB) == sys_IN_ATTRIB) -} - -// IsRename reports whether the FileEvent was triggered by a change name -func (e *FileEvent) IsRename() bool { - return ((e.mask&sys_IN_MOVE_SELF) == sys_IN_MOVE_SELF || (e.mask&sys_IN_MOVED_FROM) == sys_IN_MOVED_FROM) -} - -// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata. -func (e *FileEvent) IsAttrib() bool { - return (e.mask & sys_IN_ATTRIB) == sys_IN_ATTRIB -} - -type watch struct { - wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) - flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) -} - -type Watcher struct { - mu sync.Mutex // Map access - fd int // File descriptor (as returned by the inotify_init() syscall) - watches map[string]*watch // Map of inotify watches (key: path) - fsnFlags map[string]uint32 // Map of watched files to flags used for filter - fsnmut sync.Mutex // Protects access to fsnFlags. - paths map[int]string // Map of watched paths (key: watch descriptor) - Error chan error // Errors are sent on this channel - internalEvent chan *FileEvent // Events are queued on this channel - Event chan *FileEvent // Events are returned on this channel - done chan bool // Channel for sending a "quit message" to the reader goroutine - isClosed bool // Set to true when Close() is first called -} - -// NewWatcher creates and returns a new inotify instance using inotify_init(2) -func NewWatcher() (*Watcher, error) { - fd, errno := syscall.InotifyInit() - if fd == -1 { - return nil, os.NewSyscallError("inotify_init", errno) - } - w := &Watcher{ - fd: fd, - watches: make(map[string]*watch), - fsnFlags: make(map[string]uint32), - paths: make(map[int]string), - internalEvent: make(chan *FileEvent), - Event: make(chan *FileEvent), - Error: make(chan error), - done: make(chan bool, 1), - } - - go w.readEvents() - go w.purgeEvents() - return w, nil -} - -// Close closes an inotify watcher instance -// It sends a message to the reader goroutine to quit and removes all watches -// associated with the inotify instance -func (w *Watcher) Close() error { - if w.isClosed { - return nil - } - w.isClosed = true - - // Remove all watches - for path := range w.watches { - w.RemoveWatch(path) - } - - // Send "quit" message to the reader goroutine - w.done <- true - - return nil -} - -// AddWatch adds path to the watched file set. -// The flags are interpreted as described in inotify_add_watch(2). -func (w *Watcher) addWatch(path string, flags uint32) error { - if w.isClosed { - return errors.New("inotify instance already closed") - } - - w.mu.Lock() - watchEntry, found := w.watches[path] - w.mu.Unlock() - if found { - watchEntry.flags |= flags - flags |= syscall.IN_MASK_ADD - } - wd, errno := syscall.InotifyAddWatch(w.fd, path, flags) - if wd == -1 { - return errno - } - - w.mu.Lock() - w.watches[path] = &watch{wd: uint32(wd), flags: flags} - w.paths[wd] = path - w.mu.Unlock() - - return nil -} - -// Watch adds path to the watched file set, watching all events. -func (w *Watcher) watch(path string) error { - return w.addWatch(path, sys_AGNOSTIC_EVENTS) -} - -// RemoveWatch removes path from the watched file set. -func (w *Watcher) removeWatch(path string) error { - w.mu.Lock() - defer w.mu.Unlock() - watch, ok := w.watches[path] - if !ok { - return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path)) - } - success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) - if success == -1 { - return os.NewSyscallError("inotify_rm_watch", errno) - } - delete(w.watches, path) - return nil -} - -// readEvents reads from the inotify file descriptor, converts the -// received events into Event objects and sends them via the Event channel -func (w *Watcher) readEvents() { - var ( - buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events - n int // Number of bytes read with read() - errno error // Syscall errno - ) - - for { - // See if there is a message on the "done" channel - select { - case <-w.done: - syscall.Close(w.fd) - close(w.internalEvent) - close(w.Error) - return - default: - } - - n, errno = syscall.Read(w.fd, buf[:]) - - // If EOF is received - if n == 0 { - syscall.Close(w.fd) - close(w.internalEvent) - close(w.Error) - return - } - - if n < 0 { - w.Error <- os.NewSyscallError("read", errno) - continue - } - if n < syscall.SizeofInotifyEvent { - w.Error <- errors.New("inotify: short read in readEvents()") - continue - } - - var offset uint32 = 0 - // We don't know how many events we just read into the buffer - // While the offset points to at least one whole event... - for offset <= uint32(n-syscall.SizeofInotifyEvent) { - // Point "raw" to the event in the buffer - raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) - event := new(FileEvent) - event.mask = uint32(raw.Mask) - event.cookie = uint32(raw.Cookie) - nameLen := uint32(raw.Len) - // If the event happened to the watched directory or the watched file, the kernel - // doesn't append the filename to the event, but we would like to always fill the - // the "Name" field with a valid filename. We retrieve the path of the watch from - // the "paths" map. - w.mu.Lock() - event.Name = w.paths[int(raw.Wd)] - w.mu.Unlock() - watchedName := event.Name - if nameLen > 0 { - // Point "bytes" at the first byte of the filename - bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent])) - // The filename is padded with NUL bytes. TrimRight() gets rid of those. - event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") - } - - // Send the events that are not ignored on the events channel - if !event.ignoreLinux() { - // Setup FSNotify flags (inherit from directory watch) - w.fsnmut.Lock() - if _, fsnFound := w.fsnFlags[event.Name]; !fsnFound { - if fsnFlags, watchFound := w.fsnFlags[watchedName]; watchFound { - w.fsnFlags[event.Name] = fsnFlags - } else { - w.fsnFlags[event.Name] = FSN_ALL - } - } - w.fsnmut.Unlock() - - w.internalEvent <- event - } - - // Move to the next event in the buffer - offset += syscall.SizeofInotifyEvent + nameLen - } - } -} - -// Certain types of events can be "ignored" and not sent over the Event -// channel. Such as events marked ignore by the kernel, or MODIFY events -// against files that do not exist. -func (e *FileEvent) ignoreLinux() bool { - // Ignore anything the inotify API says to ignore - if e.mask&sys_IN_IGNORED == sys_IN_IGNORED { - return true - } - - // If the event is not a DELETE or RENAME, the file must exist. - // Otherwise the event is ignored. - // *Note*: this was put in place because it was seen that a MODIFY - // event was sent after the DELETE. This ignores that MODIFY and - // assumes a DELETE will come or has come if the file doesn't exist. - if !(e.IsDelete() || e.IsRename()) { - _, statErr := os.Lstat(e.Name) - return os.IsNotExist(statErr) - } - return false -} diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go b/vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go deleted file mode 100644 index f728a6f..0000000 --- a/vendor/github.com/howeyc/fsnotify/fsnotify_open_bsd.go +++ /dev/null @@ -1,11 +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 openbsd netbsd dragonfly - -package fsnotify - -import "syscall" - -const open_FLAGS = syscall.O_NONBLOCK | syscall.O_RDONLY diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go b/vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go deleted file mode 100644 index d450318..0000000 --- a/vendor/github.com/howeyc/fsnotify/fsnotify_open_darwin.go +++ /dev/null @@ -1,11 +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 darwin - -package fsnotify - -import "syscall" - -const open_FLAGS = syscall.O_EVTONLY diff --git a/vendor/github.com/howeyc/fsnotify/fsnotify_windows.go b/vendor/github.com/howeyc/fsnotify/fsnotify_windows.go deleted file mode 100644 index d88ae63..0000000 --- a/vendor/github.com/howeyc/fsnotify/fsnotify_windows.go +++ /dev/null @@ -1,598 +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 windows - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "runtime" - "sync" - "syscall" - "unsafe" -) - -const ( - // Options for AddWatch - sys_FS_ONESHOT = 0x80000000 - sys_FS_ONLYDIR = 0x1000000 - - // Events - sys_FS_ACCESS = 0x1 - sys_FS_ALL_EVENTS = 0xfff - sys_FS_ATTRIB = 0x4 - sys_FS_CLOSE = 0x18 - sys_FS_CREATE = 0x100 - sys_FS_DELETE = 0x200 - sys_FS_DELETE_SELF = 0x400 - sys_FS_MODIFY = 0x2 - sys_FS_MOVE = 0xc0 - sys_FS_MOVED_FROM = 0x40 - sys_FS_MOVED_TO = 0x80 - sys_FS_MOVE_SELF = 0x800 - - // Special events - sys_FS_IGNORED = 0x8000 - sys_FS_Q_OVERFLOW = 0x4000 -) - -const ( - // TODO(nj): Use syscall.ERROR_MORE_DATA from ztypes_windows in Go 1.3+ - sys_ERROR_MORE_DATA syscall.Errno = 234 -) - -// Event is the type of the notification messages -// received on the watcher's Event channel. -type FileEvent struct { - mask uint32 // Mask of events - cookie uint32 // Unique cookie associating related events (for rename) - Name string // File name (optional) -} - -// IsCreate reports whether the FileEvent was triggered by a creation -func (e *FileEvent) IsCreate() bool { return (e.mask & sys_FS_CREATE) == sys_FS_CREATE } - -// IsDelete reports whether the FileEvent was triggered by a delete -func (e *FileEvent) IsDelete() bool { - return ((e.mask&sys_FS_DELETE) == sys_FS_DELETE || (e.mask&sys_FS_DELETE_SELF) == sys_FS_DELETE_SELF) -} - -// IsModify reports whether the FileEvent was triggered by a file modification or attribute change -func (e *FileEvent) IsModify() bool { - return ((e.mask&sys_FS_MODIFY) == sys_FS_MODIFY || (e.mask&sys_FS_ATTRIB) == sys_FS_ATTRIB) -} - -// IsRename reports whether the FileEvent was triggered by a change name -func (e *FileEvent) IsRename() bool { - return ((e.mask&sys_FS_MOVE) == sys_FS_MOVE || (e.mask&sys_FS_MOVE_SELF) == sys_FS_MOVE_SELF || (e.mask&sys_FS_MOVED_FROM) == sys_FS_MOVED_FROM || (e.mask&sys_FS_MOVED_TO) == sys_FS_MOVED_TO) -} - -// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata. -func (e *FileEvent) IsAttrib() bool { - return (e.mask & sys_FS_ATTRIB) == sys_FS_ATTRIB -} - -const ( - opAddWatch = iota - opRemoveWatch -) - -const ( - provisional uint64 = 1 << (32 + iota) -) - -type input struct { - op int - path string - flags uint32 - reply chan error -} - -type inode struct { - handle syscall.Handle - volume uint32 - index uint64 -} - -type watch struct { - ov syscall.Overlapped - ino *inode // i-number - path string // Directory path - mask uint64 // Directory itself is being watched with these notify flags - names map[string]uint64 // Map of names being watched and their notify flags - rename string // Remembers the old name while renaming a file - buf [4096]byte -} - -type indexMap map[uint64]*watch -type watchMap map[uint32]indexMap - -// A Watcher waits for and receives event notifications -// for a specific set of files and directories. -type Watcher struct { - mu sync.Mutex // Map access - port syscall.Handle // Handle to completion port - watches watchMap // Map of watches (key: i-number) - fsnFlags map[string]uint32 // Map of watched files to flags used for filter - fsnmut sync.Mutex // Protects access to fsnFlags. - input chan *input // Inputs to the reader are sent on this channel - internalEvent chan *FileEvent // Events are queued on this channel - Event chan *FileEvent // Events are returned on this channel - Error chan error // Errors are sent on this channel - isClosed bool // Set to true when Close() is first called - quit chan chan<- error - cookie uint32 -} - -// NewWatcher creates and returns a Watcher. -func NewWatcher() (*Watcher, error) { - port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) - if e != nil { - return nil, os.NewSyscallError("CreateIoCompletionPort", e) - } - w := &Watcher{ - port: port, - watches: make(watchMap), - fsnFlags: make(map[string]uint32), - input: make(chan *input, 1), - Event: make(chan *FileEvent, 50), - internalEvent: make(chan *FileEvent), - Error: make(chan error), - quit: make(chan chan<- error, 1), - } - go w.readEvents() - go w.purgeEvents() - return w, nil -} - -// Close closes a Watcher. -// It sends a message to the reader goroutine to quit and removes all watches -// associated with the watcher. -func (w *Watcher) Close() error { - if w.isClosed { - return nil - } - w.isClosed = true - - // Send "quit" message to the reader goroutine - ch := make(chan error) - w.quit <- ch - if err := w.wakeupReader(); err != nil { - return err - } - return <-ch -} - -// AddWatch adds path to the watched file set. -func (w *Watcher) AddWatch(path string, flags uint32) error { - if w.isClosed { - return errors.New("watcher already closed") - } - in := &input{ - op: opAddWatch, - path: filepath.Clean(path), - flags: flags, - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -// Watch adds path to the watched file set, watching all events. -func (w *Watcher) watch(path string) error { - return w.AddWatch(path, sys_FS_ALL_EVENTS) -} - -// RemoveWatch removes path from the watched file set. -func (w *Watcher) removeWatch(path string) error { - in := &input{ - op: opRemoveWatch, - path: filepath.Clean(path), - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -func (w *Watcher) wakeupReader() error { - e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) - if e != nil { - return os.NewSyscallError("PostQueuedCompletionStatus", e) - } - return nil -} - -func getDir(pathname string) (dir string, err error) { - attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) - if e != nil { - return "", os.NewSyscallError("GetFileAttributes", e) - } - if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - dir = pathname - } else { - dir, _ = filepath.Split(pathname) - dir = filepath.Clean(dir) - } - return -} - -func getIno(path string) (ino *inode, err error) { - h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), - syscall.FILE_LIST_DIRECTORY, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - nil, syscall.OPEN_EXISTING, - syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) - if e != nil { - return nil, os.NewSyscallError("CreateFile", e) - } - var fi syscall.ByHandleFileInformation - if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { - syscall.CloseHandle(h) - return nil, os.NewSyscallError("GetFileInformationByHandle", e) - } - ino = &inode{ - handle: h, - volume: fi.VolumeSerialNumber, - index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), - } - return ino, nil -} - -// Must run within the I/O thread. -func (m watchMap) get(ino *inode) *watch { - if i := m[ino.volume]; i != nil { - return i[ino.index] - } - return nil -} - -// Must run within the I/O thread. -func (m watchMap) set(ino *inode, watch *watch) { - i := m[ino.volume] - if i == nil { - i = make(indexMap) - m[ino.volume] = i - } - i[ino.index] = watch -} - -// Must run within the I/O thread. -func (w *Watcher) addWatch(pathname string, flags uint64) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - if flags&sys_FS_ONLYDIR != 0 && pathname != dir { - return nil - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watchEntry := w.watches.get(ino) - w.mu.Unlock() - if watchEntry == nil { - if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { - syscall.CloseHandle(ino.handle) - return os.NewSyscallError("CreateIoCompletionPort", e) - } - watchEntry = &watch{ - ino: ino, - path: dir, - names: make(map[string]uint64), - } - w.mu.Lock() - w.watches.set(ino, watchEntry) - w.mu.Unlock() - flags |= provisional - } else { - syscall.CloseHandle(ino.handle) - } - if pathname == dir { - watchEntry.mask |= flags - } else { - watchEntry.names[filepath.Base(pathname)] |= flags - } - if err = w.startRead(watchEntry); err != nil { - return err - } - if pathname == dir { - watchEntry.mask &= ^provisional - } else { - watchEntry.names[filepath.Base(pathname)] &= ^provisional - } - return nil -} - -// Must run within the I/O thread. -func (w *Watcher) remWatch(pathname string) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watch := w.watches.get(ino) - w.mu.Unlock() - if watch == nil { - return fmt.Errorf("can't remove non-existent watch for: %s", pathname) - } - if pathname == dir { - w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED) - watch.mask = 0 - } else { - name := filepath.Base(pathname) - w.sendEvent(watch.path+"\\"+name, watch.names[name]&sys_FS_IGNORED) - delete(watch.names, name) - } - return w.startRead(watch) -} - -// Must run within the I/O thread. -func (w *Watcher) deleteWatch(watch *watch) { - for name, mask := range watch.names { - if mask&provisional == 0 { - w.sendEvent(watch.path+"\\"+name, mask&sys_FS_IGNORED) - } - delete(watch.names, name) - } - if watch.mask != 0 { - if watch.mask&provisional == 0 { - w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED) - } - watch.mask = 0 - } -} - -// Must run within the I/O thread. -func (w *Watcher) startRead(watch *watch) error { - if e := syscall.CancelIo(watch.ino.handle); e != nil { - w.Error <- os.NewSyscallError("CancelIo", e) - w.deleteWatch(watch) - } - mask := toWindowsFlags(watch.mask) - for _, m := range watch.names { - mask |= toWindowsFlags(m) - } - if mask == 0 { - if e := syscall.CloseHandle(watch.ino.handle); e != nil { - w.Error <- os.NewSyscallError("CloseHandle", e) - } - w.mu.Lock() - delete(w.watches[watch.ino.volume], watch.ino.index) - w.mu.Unlock() - return nil - } - e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], - uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) - if e != nil { - err := os.NewSyscallError("ReadDirectoryChanges", e) - if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { - // Watched directory was probably removed - if w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) { - if watch.mask&sys_FS_ONESHOT != 0 { - watch.mask = 0 - } - } - err = nil - } - w.deleteWatch(watch) - w.startRead(watch) - return err - } - return nil -} - -// readEvents reads from the I/O completion port, converts the -// received events into Event objects and sends them via the Event channel. -// Entry point to the I/O thread. -func (w *Watcher) readEvents() { - var ( - n, key uint32 - ov *syscall.Overlapped - ) - runtime.LockOSThread() - - for { - e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) - watch := (*watch)(unsafe.Pointer(ov)) - - if watch == nil { - select { - case ch := <-w.quit: - w.mu.Lock() - var indexes []indexMap - for _, index := range w.watches { - indexes = append(indexes, index) - } - w.mu.Unlock() - for _, index := range indexes { - for _, watch := range index { - w.deleteWatch(watch) - w.startRead(watch) - } - } - var err error - if e := syscall.CloseHandle(w.port); e != nil { - err = os.NewSyscallError("CloseHandle", e) - } - close(w.internalEvent) - close(w.Error) - ch <- err - return - case in := <-w.input: - switch in.op { - case opAddWatch: - in.reply <- w.addWatch(in.path, uint64(in.flags)) - case opRemoveWatch: - in.reply <- w.remWatch(in.path) - } - default: - } - continue - } - - switch e { - case sys_ERROR_MORE_DATA: - if watch == nil { - w.Error <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") - } else { - // The i/o succeeded but the buffer is full. - // In theory we should be building up a full packet. - // In practice we can get away with just carrying on. - n = uint32(unsafe.Sizeof(watch.buf)) - } - case syscall.ERROR_ACCESS_DENIED: - // Watched directory was probably removed - w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) - w.deleteWatch(watch) - w.startRead(watch) - continue - case syscall.ERROR_OPERATION_ABORTED: - // CancelIo was called on this handle - continue - default: - w.Error <- os.NewSyscallError("GetQueuedCompletionPort", e) - continue - case nil: - } - - var offset uint32 - for { - if n == 0 { - w.internalEvent <- &FileEvent{mask: sys_FS_Q_OVERFLOW} - w.Error <- errors.New("short read in readEvents()") - break - } - - // Point "raw" to the event in the buffer - raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) - buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName)) - name := syscall.UTF16ToString(buf[:raw.FileNameLength/2]) - fullname := watch.path + "\\" + name - - var mask uint64 - switch raw.Action { - case syscall.FILE_ACTION_REMOVED: - mask = sys_FS_DELETE_SELF - case syscall.FILE_ACTION_MODIFIED: - mask = sys_FS_MODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - watch.rename = name - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - if watch.names[watch.rename] != 0 { - watch.names[name] |= watch.names[watch.rename] - delete(watch.names, watch.rename) - mask = sys_FS_MOVE_SELF - } - } - - sendNameEvent := func() { - if w.sendEvent(fullname, watch.names[name]&mask) { - if watch.names[name]&sys_FS_ONESHOT != 0 { - delete(watch.names, name) - } - } - } - if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { - sendNameEvent() - } - if raw.Action == syscall.FILE_ACTION_REMOVED { - w.sendEvent(fullname, watch.names[name]&sys_FS_IGNORED) - delete(watch.names, name) - } - if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { - if watch.mask&sys_FS_ONESHOT != 0 { - watch.mask = 0 - } - } - if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { - fullname = watch.path + "\\" + watch.rename - sendNameEvent() - } - - // Move to the next event in the buffer - if raw.NextEntryOffset == 0 { - break - } - offset += raw.NextEntryOffset - - // Error! - if offset >= n { - w.Error <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") - break - } - } - - if err := w.startRead(watch); err != nil { - w.Error <- err - } - } -} - -func (w *Watcher) sendEvent(name string, mask uint64) bool { - if mask == 0 { - return false - } - event := &FileEvent{mask: uint32(mask), Name: name} - if mask&sys_FS_MOVE != 0 { - if mask&sys_FS_MOVED_FROM != 0 { - w.cookie++ - } - event.cookie = w.cookie - } - select { - case ch := <-w.quit: - w.quit <- ch - case w.Event <- event: - } - return true -} - -func toWindowsFlags(mask uint64) uint32 { - var m uint32 - if mask&sys_FS_ACCESS != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS - } - if mask&sys_FS_MODIFY != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE - } - if mask&sys_FS_ATTRIB != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES - } - if mask&(sys_FS_MOVE|sys_FS_CREATE|sys_FS_DELETE) != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME - } - return m -} - -func toFSnotifyFlags(action uint32) uint64 { - switch action { - case syscall.FILE_ACTION_ADDED: - return sys_FS_CREATE - case syscall.FILE_ACTION_REMOVED: - return sys_FS_DELETE - case syscall.FILE_ACTION_MODIFIED: - return sys_FS_MODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - return sys_FS_MOVED_FROM - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - return sys_FS_MOVED_TO - } - return 0 -} diff --git a/vendor/github.com/jtolds/gls/README.md b/vendor/github.com/jtolds/gls/README.md deleted file mode 100644 index 4ebb692..0000000 --- a/vendor/github.com/jtolds/gls/README.md +++ /dev/null @@ -1,89 +0,0 @@ -gls -=== - -Goroutine local storage - -### IMPORTANT NOTE ### - -It is my duty to point you to https://blog.golang.org/context, which is how -Google solves all of the problems you'd perhaps consider using this package -for at scale. - -One downside to Google's approach is that *all* of your functions must have -a new first argument, but after clearing that hurdle everything else is much -better. - -If you aren't interested in this warning, read on. - -### Huhwaht? Why? ### - -Every so often, a thread shows up on the -[golang-nuts](https://groups.google.com/d/forum/golang-nuts) asking for some -form of goroutine-local-storage, or some kind of goroutine id, or some kind of -context. There are a few valid use cases for goroutine-local-storage, one of -the most prominent being log line context. One poster was interested in being -able to log an HTTP request context id in every log line in the same goroutine -as the incoming HTTP request, without having to change every library and -function call he was interested in logging. - -This would be pretty useful. Provided that you could get some kind of -goroutine-local-storage, you could call -[log.SetOutput](http://golang.org/pkg/log/#SetOutput) with your own logging -writer that checks goroutine-local-storage for some context information and -adds that context to your log lines. - -But alas, Andrew Gerrand's typically diplomatic answer to the question of -goroutine-local variables was: - -> We wouldn't even be having this discussion if thread local storage wasn't -> useful. But every feature comes at a cost, and in my opinion the cost of -> threadlocals far outweighs their benefits. They're just not a good fit for -> Go. - -So, yeah, that makes sense. That's a pretty good reason for why the language -won't support a specific and (relatively) unuseful feature that requires some -runtime changes, just for the sake of a little bit of log improvement. - -But does Go require runtime changes? - -### How it works ### - -Go has pretty fantastic introspective and reflective features, but one thing Go -doesn't give you is any kind of access to the stack pointer, or frame pointer, -or goroutine id, or anything contextual about your current stack. It gives you -access to your list of callers, but only along with program counters, which are -fixed at compile time. - -But it does give you the stack. - -So, we define 16 special functions and embed base-16 tags into the stack using -the call order of those 16 functions. Then, we can read our tags back out of -the stack looking at the callers list. - -We then use these tags as an index into a traditional map for implementing -this library. - -### What are people saying? ### - -"Wow, that's horrifying." - -"This is the most terrible thing I have seen in a very long time." - -"Where is it getting a context from? Is this serializing all the requests? -What the heck is the client being bound to? What are these tags? Why does he -need callers? Oh god no. No no no." - -### Docs ### - -Please see the docs at http://godoc.org/github.com/jtolds/gls - -### Related ### - -If you're okay relying on the string format of the current runtime stacktrace -including a unique goroutine id (not guaranteed by the spec or anything, but -very unlikely to change within a Go release), you might be able to squeeze -out a bit more performance by using this similar library, inspired by some -code Brad Fitzpatrick wrote for debugging his HTTP/2 library: -https://github.com/tylerb/gls (in contrast, jtolds/gls doesn't require -any knowledge of the string format of the runtime stacktrace, which -probably adds unnecessary overhead). diff --git a/vendor/github.com/jtolds/gls/context.go b/vendor/github.com/jtolds/gls/context.go deleted file mode 100644 index 90cfcf7..0000000 --- a/vendor/github.com/jtolds/gls/context.go +++ /dev/null @@ -1,144 +0,0 @@ -// Package gls implements goroutine-local storage. -package gls - -import ( - "sync" -) - -const ( - maxCallers = 64 -) - -var ( - stackTagPool = &idPool{} - mgrRegistry = make(map[*ContextManager]bool) - mgrRegistryMtx sync.RWMutex -) - -// Values is simply a map of key types to value types. Used by SetValues to -// set multiple values at once. -type Values map[interface{}]interface{} - -// ContextManager is the main entrypoint for interacting with -// Goroutine-local-storage. You can have multiple independent ContextManagers -// at any given time. ContextManagers are usually declared globally for a given -// class of context variables. You should use NewContextManager for -// construction. -type ContextManager struct { - mtx sync.RWMutex - values map[uint]Values -} - -// NewContextManager returns a brand new ContextManager. It also registers the -// new ContextManager in the ContextManager registry which is used by the Go -// method. ContextManagers are typically defined globally at package scope. -func NewContextManager() *ContextManager { - mgr := &ContextManager{values: make(map[uint]Values)} - mgrRegistryMtx.Lock() - defer mgrRegistryMtx.Unlock() - mgrRegistry[mgr] = true - return mgr -} - -// Unregister removes a ContextManager from the global registry, used by the -// Go method. Only intended for use when you're completely done with a -// ContextManager. Use of Unregister at all is rare. -func (m *ContextManager) Unregister() { - mgrRegistryMtx.Lock() - defer mgrRegistryMtx.Unlock() - delete(mgrRegistry, m) -} - -// SetValues takes a collection of values and a function to call for those -// values to be set in. Anything further down the stack will have the set -// values available through GetValue. SetValues will add new values or replace -// existing values of the same key and will not mutate or change values for -// previous stack frames. -// SetValues is slow (makes a copy of all current and new values for the new -// gls-context) in order to reduce the amount of lookups GetValue requires. -func (m *ContextManager) SetValues(new_values Values, context_call func()) { - if len(new_values) == 0 { - context_call() - return - } - - tags := readStackTags(1) - - m.mtx.Lock() - values := new_values - for _, tag := range tags { - if existing_values, ok := m.values[tag]; ok { - // oh, we found existing values, let's make a copy - values = make(Values, len(existing_values)+len(new_values)) - for key, val := range existing_values { - values[key] = val - } - for key, val := range new_values { - values[key] = val - } - break - } - } - new_tag := stackTagPool.Acquire() - m.values[new_tag] = values - m.mtx.Unlock() - defer func() { - m.mtx.Lock() - delete(m.values, new_tag) - m.mtx.Unlock() - stackTagPool.Release(new_tag) - }() - - addStackTag(new_tag, context_call) -} - -// GetValue will return a previously set value, provided that the value was set -// by SetValues somewhere higher up the stack. If the value is not found, ok -// will be false. -func (m *ContextManager) GetValue(key interface{}) (value interface{}, ok bool) { - - tags := readStackTags(1) - m.mtx.RLock() - defer m.mtx.RUnlock() - for _, tag := range tags { - if values, ok := m.values[tag]; ok { - value, ok := values[key] - return value, ok - } - } - return "", false -} - -func (m *ContextManager) getValues() Values { - tags := readStackTags(2) - m.mtx.RLock() - defer m.mtx.RUnlock() - for _, tag := range tags { - if values, ok := m.values[tag]; ok { - return values - } - } - return nil -} - -// Go preserves ContextManager values and Goroutine-local-storage across new -// goroutine invocations. The Go method makes a copy of all existing values on -// all registered context managers and makes sure they are still set after -// kicking off the provided function in a new goroutine. If you don't use this -// Go method instead of the standard 'go' keyword, you will lose values in -// ContextManagers, as goroutines have brand new stacks. -func Go(cb func()) { - mgrRegistryMtx.RLock() - defer mgrRegistryMtx.RUnlock() - - for mgr, _ := range mgrRegistry { - values := mgr.getValues() - if len(values) > 0 { - mgr_copy := mgr - cb_copy := cb - cb = func() { mgr_copy.SetValues(values, cb_copy) } - } - } - - go cb() -} diff --git a/vendor/github.com/jtolds/gls/gen_sym.go b/vendor/github.com/jtolds/gls/gen_sym.go deleted file mode 100644 index 8d5fc24..0000000 --- a/vendor/github.com/jtolds/gls/gen_sym.go +++ /dev/null @@ -1,13 +0,0 @@ -package gls - -var ( - symPool = &idPool{} -) - -// ContextKey is a throwaway value you can use as a key to a ContextManager -type ContextKey struct{ id uint } - -// GenSym will return a brand new, never-before-used ContextKey -func GenSym() ContextKey { - return ContextKey{id: symPool.Acquire()} -} diff --git a/vendor/github.com/jtolds/gls/id_pool.go b/vendor/github.com/jtolds/gls/id_pool.go deleted file mode 100644 index b7974ae..0000000 --- a/vendor/github.com/jtolds/gls/id_pool.go +++ /dev/null @@ -1,34 +0,0 @@ -package gls - -// though this could probably be better at keeping ids smaller, the goal of -// this class is to keep a registry of the smallest unique integer ids -// per-process possible - -import ( - "sync" -) - -type idPool struct { - mtx sync.Mutex - released []uint - max_id uint -} - -func (p *idPool) Acquire() (id uint) { - p.mtx.Lock() - defer p.mtx.Unlock() - if len(p.released) > 0 { - id = p.released[len(p.released)-1] - p.released = p.released[:len(p.released)-1] - return id - } - id = p.max_id - p.max_id++ - return id -} - -func (p *idPool) Release(id uint) { - p.mtx.Lock() - defer p.mtx.Unlock() - p.released = append(p.released, id) -} diff --git a/vendor/github.com/jtolds/gls/stack_tags.go b/vendor/github.com/jtolds/gls/stack_tags.go deleted file mode 100644 index 9b8e39b..0000000 --- a/vendor/github.com/jtolds/gls/stack_tags.go +++ /dev/null @@ -1,43 +0,0 @@ -package gls - -// so, basically, we're going to encode integer tags in base-16 on the stack - -const ( - bitWidth = 4 -) - -func addStackTag(tag uint, context_call func()) { - if context_call == nil { - return - } - markS(tag, context_call) -} - -func markS(tag uint, cb func()) { _m(tag, cb) } -func mark0(tag uint, cb func()) { _m(tag, cb) } -func mark1(tag uint, cb func()) { _m(tag, cb) } -func mark2(tag uint, cb func()) { _m(tag, cb) } -func mark3(tag uint, cb func()) { _m(tag, cb) } -func mark4(tag uint, cb func()) { _m(tag, cb) } -func mark5(tag uint, cb func()) { _m(tag, cb) } -func mark6(tag uint, cb func()) { _m(tag, cb) } -func mark7(tag uint, cb func()) { _m(tag, cb) } -func mark8(tag uint, cb func()) { _m(tag, cb) } -func mark9(tag uint, cb func()) { _m(tag, cb) } -func markA(tag uint, cb func()) { _m(tag, cb) } -func markB(tag uint, cb func()) { _m(tag, cb) } -func markC(tag uint, cb func()) { _m(tag, cb) } -func markD(tag uint, cb func()) { _m(tag, cb) } -func markE(tag uint, cb func()) { _m(tag, cb) } -func markF(tag uint, cb func()) { _m(tag, cb) } - -var pc_lookup = make(map[uintptr]int8, 17) -var mark_lookup [16]func(uint, func()) - -func _m(tag_remainder uint, cb func()) { - if tag_remainder == 0 { - cb() - } else { - mark_lookup[tag_remainder&0xf](tag_remainder>>bitWidth, cb) - } -} diff --git a/vendor/github.com/jtolds/gls/stack_tags_js.go b/vendor/github.com/jtolds/gls/stack_tags_js.go deleted file mode 100644 index 21d5595..0000000 --- a/vendor/github.com/jtolds/gls/stack_tags_js.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build js - -package gls - -// This file is used for GopherJS builds, which don't have normal runtime support - -import ( - "regexp" - "strconv" - "strings" - - "github.com/gopherjs/gopherjs/js" -) - -var stackRE = regexp.MustCompile("\\s+at (\\S*) \\([^:]+:(\\d+):(\\d+)") - -func findPtr() uintptr { - jsStack := js.Global.Get("Error").New().Get("stack").Call("split", "\n") - for i := 1; i < jsStack.Get("length").Int(); i++ { - item := jsStack.Index(i).String() - matches := stackRE.FindAllStringSubmatch(item, -1) - if matches == nil { - return 0 - } - pkgPath := matches[0][1] - if strings.HasPrefix(pkgPath, "$packages.github.com/jtolds/gls.mark") { - line, _ := strconv.Atoi(matches[0][2]) - char, _ := strconv.Atoi(matches[0][3]) - x := (uintptr(line) << 16) | uintptr(char) - return x - } - } - - return 0 -} - -func init() { - setEntries := func(f func(uint, func()), v int8) { - var ptr uintptr - f(0, func() { - ptr = findPtr() - }) - pc_lookup[ptr] = v - if v >= 0 { - mark_lookup[v] = f - } - } - setEntries(markS, -0x1) - setEntries(mark0, 0x0) - setEntries(mark1, 0x1) - setEntries(mark2, 0x2) - setEntries(mark3, 0x3) - setEntries(mark4, 0x4) - setEntries(mark5, 0x5) - setEntries(mark6, 0x6) - setEntries(mark7, 0x7) - setEntries(mark8, 0x8) - setEntries(mark9, 0x9) - setEntries(markA, 0xa) - setEntries(markB, 0xb) - setEntries(markC, 0xc) - setEntries(markD, 0xd) - setEntries(markE, 0xe) - setEntries(markF, 0xf) -} - -func currentStack(skip int) (stack []uintptr) { - jsStack := js.Global.Get("Error").New().Get("stack").Call("split", "\n") - for i := skip + 2; i < jsStack.Get("length").Int(); i++ { - item := jsStack.Index(i).String() - matches := stackRE.FindAllStringSubmatch(item, -1) - if matches == nil { - return stack - } - line, _ := strconv.Atoi(matches[0][2]) - char, _ := strconv.Atoi(matches[0][3]) - x := (uintptr(line) << 16) | uintptr(char)&0xffff - stack = append(stack, x) - } - - return stack -} - -func readStackTags(skip int) (tags []uint) { - stack := currentStack(skip) - var current_tag uint - for _, pc := range stack { - val, ok := pc_lookup[pc] - if !ok { - continue - } - if val < 0 { - tags = append(tags, current_tag) - current_tag = 0 - continue - } - current_tag <<= bitWidth - current_tag += uint(val) - } - return -} diff --git a/vendor/github.com/jtolds/gls/stack_tags_main.go b/vendor/github.com/jtolds/gls/stack_tags_main.go deleted file mode 100644 index cb302b9..0000000 --- a/vendor/github.com/jtolds/gls/stack_tags_main.go +++ /dev/null @@ -1,61 +0,0 @@ -// +build !js - -package gls - -// This file is used for standard Go builds, which have the expected runtime support - -import ( - "reflect" - "runtime" -) - -func init() { - setEntries := func(f func(uint, func()), v int8) { - pc_lookup[reflect.ValueOf(f).Pointer()] = v - if v >= 0 { - mark_lookup[v] = f - } - } - setEntries(markS, -0x1) - setEntries(mark0, 0x0) - setEntries(mark1, 0x1) - setEntries(mark2, 0x2) - setEntries(mark3, 0x3) - setEntries(mark4, 0x4) - setEntries(mark5, 0x5) - setEntries(mark6, 0x6) - setEntries(mark7, 0x7) - setEntries(mark8, 0x8) - setEntries(mark9, 0x9) - setEntries(markA, 0xa) - setEntries(markB, 0xb) - setEntries(markC, 0xc) - setEntries(markD, 0xd) - setEntries(markE, 0xe) - setEntries(markF, 0xf) -} - -func currentStack(skip int) []uintptr { - stack := make([]uintptr, maxCallers) - return stack[:runtime.Callers(3+skip, stack)] -} - -func readStackTags(skip int) (tags []uint) { - stack := currentStack(skip) - var current_tag uint - for _, pc := range stack { - pc = runtime.FuncForPC(pc).Entry() - val, ok := pc_lookup[pc] - if !ok { - continue - } - if val < 0 { - tags = append(tags, current_tag) - current_tag = 0 - continue - } - current_tag <<= bitWidth - current_tag += uint(val) - } - return -} diff --git a/vendor/github.com/smartystreets/goconvey/LICENSE.md b/vendor/github.com/mattn/go-colorable/LICENSE similarity index 79% rename from vendor/github.com/smartystreets/goconvey/LICENSE.md rename to vendor/github.com/mattn/go-colorable/LICENSE index 5bc993c..91b5cef 100644 --- a/vendor/github.com/smartystreets/goconvey/LICENSE.md +++ b/vendor/github.com/mattn/go-colorable/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2014 SmartyStreets, LLC +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -17,7 +19,3 @@ 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. - -NOTE: Various optional and subordinate components carry their own licensing -requirements and restrictions. Use of those components is subject to the terms -and conditions outlined the respective license of each component. diff --git a/vendor/github.com/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md new file mode 100644 index 0000000..e84226a --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/README.md @@ -0,0 +1,43 @@ +# go-colorable + +Colorable writer for windows. + +For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) +This package is possible to handle escape sequence for ansi color on windows. + +## Too Bad! + +![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) + + +## So Good! + +![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) + +## Usage + +```go +logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) +logrus.SetOutput(colorable.NewColorableStdout()) + +logrus.Info("succeeded") +logrus.Warn("not correct") +logrus.Error("something error") +logrus.Fatal("panic") +``` + +You can compile above code on non-windows OSs. + +## Installation + +``` +$ go get github.com/mattn/go-colorable +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go new file mode 100644 index 0000000..52d6653 --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -0,0 +1,24 @@ +// +build !windows + +package colorable + +import ( + "io" + "os" +) + +func NewColorable(file *os.File) io.Writer { + if file == nil { + panic("nil passed instead of *os.File to NewColorable()") + } + + return file +} + +func NewColorableStdout() io.Writer { + return os.Stdout +} + +func NewColorableStderr() io.Writer { + return os.Stderr +} diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go new file mode 100644 index 0000000..c8f4e09 --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -0,0 +1,783 @@ +package colorable + +import ( + "bytes" + "fmt" + "io" + "math" + "os" + "strconv" + "strings" + "syscall" + "unsafe" + + "github.com/mattn/go-isatty" +) + +const ( + foregroundBlue = 0x1 + foregroundGreen = 0x2 + foregroundRed = 0x4 + foregroundIntensity = 0x8 + foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) + backgroundBlue = 0x10 + backgroundGreen = 0x20 + backgroundRed = 0x40 + backgroundIntensity = 0x80 + backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) +) + +type wchar uint16 +type short int16 +type dword uint32 +type word uint16 + +type coord struct { + x short + y short +} + +type smallRect struct { + left short + top short + right short + bottom short +} + +type consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord +} + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") + procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") +) + +type Writer struct { + out io.Writer + handle syscall.Handle + lastbuf bytes.Buffer + oldattr word +} + +func NewColorable(file *os.File) io.Writer { + if file == nil { + panic("nil passed instead of *os.File to NewColorable()") + } + + if isatty.IsTerminal(file.Fd()) { + var csbi consoleScreenBufferInfo + handle := syscall.Handle(file.Fd()) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + return &Writer{out: file, handle: handle, oldattr: csbi.attributes} + } else { + return file + } +} + +func NewColorableStdout() io.Writer { + return NewColorable(os.Stdout) +} + +func NewColorableStderr() io.Writer { + return NewColorable(os.Stderr) +} + +var color256 = map[int]int{ + 0: 0x000000, + 1: 0x800000, + 2: 0x008000, + 3: 0x808000, + 4: 0x000080, + 5: 0x800080, + 6: 0x008080, + 7: 0xc0c0c0, + 8: 0x808080, + 9: 0xff0000, + 10: 0x00ff00, + 11: 0xffff00, + 12: 0x0000ff, + 13: 0xff00ff, + 14: 0x00ffff, + 15: 0xffffff, + 16: 0x000000, + 17: 0x00005f, + 18: 0x000087, + 19: 0x0000af, + 20: 0x0000d7, + 21: 0x0000ff, + 22: 0x005f00, + 23: 0x005f5f, + 24: 0x005f87, + 25: 0x005faf, + 26: 0x005fd7, + 27: 0x005fff, + 28: 0x008700, + 29: 0x00875f, + 30: 0x008787, + 31: 0x0087af, + 32: 0x0087d7, + 33: 0x0087ff, + 34: 0x00af00, + 35: 0x00af5f, + 36: 0x00af87, + 37: 0x00afaf, + 38: 0x00afd7, + 39: 0x00afff, + 40: 0x00d700, + 41: 0x00d75f, + 42: 0x00d787, + 43: 0x00d7af, + 44: 0x00d7d7, + 45: 0x00d7ff, + 46: 0x00ff00, + 47: 0x00ff5f, + 48: 0x00ff87, + 49: 0x00ffaf, + 50: 0x00ffd7, + 51: 0x00ffff, + 52: 0x5f0000, + 53: 0x5f005f, + 54: 0x5f0087, + 55: 0x5f00af, + 56: 0x5f00d7, + 57: 0x5f00ff, + 58: 0x5f5f00, + 59: 0x5f5f5f, + 60: 0x5f5f87, + 61: 0x5f5faf, + 62: 0x5f5fd7, + 63: 0x5f5fff, + 64: 0x5f8700, + 65: 0x5f875f, + 66: 0x5f8787, + 67: 0x5f87af, + 68: 0x5f87d7, + 69: 0x5f87ff, + 70: 0x5faf00, + 71: 0x5faf5f, + 72: 0x5faf87, + 73: 0x5fafaf, + 74: 0x5fafd7, + 75: 0x5fafff, + 76: 0x5fd700, + 77: 0x5fd75f, + 78: 0x5fd787, + 79: 0x5fd7af, + 80: 0x5fd7d7, + 81: 0x5fd7ff, + 82: 0x5fff00, + 83: 0x5fff5f, + 84: 0x5fff87, + 85: 0x5fffaf, + 86: 0x5fffd7, + 87: 0x5fffff, + 88: 0x870000, + 89: 0x87005f, + 90: 0x870087, + 91: 0x8700af, + 92: 0x8700d7, + 93: 0x8700ff, + 94: 0x875f00, + 95: 0x875f5f, + 96: 0x875f87, + 97: 0x875faf, + 98: 0x875fd7, + 99: 0x875fff, + 100: 0x878700, + 101: 0x87875f, + 102: 0x878787, + 103: 0x8787af, + 104: 0x8787d7, + 105: 0x8787ff, + 106: 0x87af00, + 107: 0x87af5f, + 108: 0x87af87, + 109: 0x87afaf, + 110: 0x87afd7, + 111: 0x87afff, + 112: 0x87d700, + 113: 0x87d75f, + 114: 0x87d787, + 115: 0x87d7af, + 116: 0x87d7d7, + 117: 0x87d7ff, + 118: 0x87ff00, + 119: 0x87ff5f, + 120: 0x87ff87, + 121: 0x87ffaf, + 122: 0x87ffd7, + 123: 0x87ffff, + 124: 0xaf0000, + 125: 0xaf005f, + 126: 0xaf0087, + 127: 0xaf00af, + 128: 0xaf00d7, + 129: 0xaf00ff, + 130: 0xaf5f00, + 131: 0xaf5f5f, + 132: 0xaf5f87, + 133: 0xaf5faf, + 134: 0xaf5fd7, + 135: 0xaf5fff, + 136: 0xaf8700, + 137: 0xaf875f, + 138: 0xaf8787, + 139: 0xaf87af, + 140: 0xaf87d7, + 141: 0xaf87ff, + 142: 0xafaf00, + 143: 0xafaf5f, + 144: 0xafaf87, + 145: 0xafafaf, + 146: 0xafafd7, + 147: 0xafafff, + 148: 0xafd700, + 149: 0xafd75f, + 150: 0xafd787, + 151: 0xafd7af, + 152: 0xafd7d7, + 153: 0xafd7ff, + 154: 0xafff00, + 155: 0xafff5f, + 156: 0xafff87, + 157: 0xafffaf, + 158: 0xafffd7, + 159: 0xafffff, + 160: 0xd70000, + 161: 0xd7005f, + 162: 0xd70087, + 163: 0xd700af, + 164: 0xd700d7, + 165: 0xd700ff, + 166: 0xd75f00, + 167: 0xd75f5f, + 168: 0xd75f87, + 169: 0xd75faf, + 170: 0xd75fd7, + 171: 0xd75fff, + 172: 0xd78700, + 173: 0xd7875f, + 174: 0xd78787, + 175: 0xd787af, + 176: 0xd787d7, + 177: 0xd787ff, + 178: 0xd7af00, + 179: 0xd7af5f, + 180: 0xd7af87, + 181: 0xd7afaf, + 182: 0xd7afd7, + 183: 0xd7afff, + 184: 0xd7d700, + 185: 0xd7d75f, + 186: 0xd7d787, + 187: 0xd7d7af, + 188: 0xd7d7d7, + 189: 0xd7d7ff, + 190: 0xd7ff00, + 191: 0xd7ff5f, + 192: 0xd7ff87, + 193: 0xd7ffaf, + 194: 0xd7ffd7, + 195: 0xd7ffff, + 196: 0xff0000, + 197: 0xff005f, + 198: 0xff0087, + 199: 0xff00af, + 200: 0xff00d7, + 201: 0xff00ff, + 202: 0xff5f00, + 203: 0xff5f5f, + 204: 0xff5f87, + 205: 0xff5faf, + 206: 0xff5fd7, + 207: 0xff5fff, + 208: 0xff8700, + 209: 0xff875f, + 210: 0xff8787, + 211: 0xff87af, + 212: 0xff87d7, + 213: 0xff87ff, + 214: 0xffaf00, + 215: 0xffaf5f, + 216: 0xffaf87, + 217: 0xffafaf, + 218: 0xffafd7, + 219: 0xffafff, + 220: 0xffd700, + 221: 0xffd75f, + 222: 0xffd787, + 223: 0xffd7af, + 224: 0xffd7d7, + 225: 0xffd7ff, + 226: 0xffff00, + 227: 0xffff5f, + 228: 0xffff87, + 229: 0xffffaf, + 230: 0xffffd7, + 231: 0xffffff, + 232: 0x080808, + 233: 0x121212, + 234: 0x1c1c1c, + 235: 0x262626, + 236: 0x303030, + 237: 0x3a3a3a, + 238: 0x444444, + 239: 0x4e4e4e, + 240: 0x585858, + 241: 0x626262, + 242: 0x6c6c6c, + 243: 0x767676, + 244: 0x808080, + 245: 0x8a8a8a, + 246: 0x949494, + 247: 0x9e9e9e, + 248: 0xa8a8a8, + 249: 0xb2b2b2, + 250: 0xbcbcbc, + 251: 0xc6c6c6, + 252: 0xd0d0d0, + 253: 0xdadada, + 254: 0xe4e4e4, + 255: 0xeeeeee, +} + +func (w *Writer) Write(data []byte) (n int, err error) { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + + er := bytes.NewBuffer(data) +loop: + for { + r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + if r1 == 0 { + break loop + } + + c1, _, err := er.ReadRune() + if err != nil { + break loop + } + if c1 != 0x1b { + fmt.Fprint(w.out, string(c1)) + continue + } + c2, _, err := er.ReadRune() + if err != nil { + w.lastbuf.WriteRune(c1) + break loop + } + if c2 != 0x5b { + w.lastbuf.WriteRune(c1) + w.lastbuf.WriteRune(c2) + continue + } + + var buf bytes.Buffer + var m rune + for { + c, _, err := er.ReadRune() + if err != nil { + w.lastbuf.WriteRune(c1) + w.lastbuf.WriteRune(c2) + w.lastbuf.Write(buf.Bytes()) + break loop + } + if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { + m = c + break + } + buf.Write([]byte(string(c))) + } + + var csbi consoleScreenBufferInfo + switch m { + case 'A': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.y -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'B': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.y += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'C': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'D': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + if n, err = strconv.Atoi(buf.String()); err == nil { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + } + case 'E': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = 0 + csbi.cursorPosition.y += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'F': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = 0 + csbi.cursorPosition.y -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'G': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'H': + token := strings.Split(buf.String(), ";") + if len(token) != 2 { + continue + } + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + n2, err := strconv.Atoi(token[1]) + if err != nil { + continue + } + csbi.cursorPosition.x = short(n2) + csbi.cursorPosition.x = short(n1) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'J': + n, err := strconv.Atoi(buf.String()) + if err != nil { + continue + } + var cursor coord + switch n { + case 0: + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + case 1: + cursor = coord{x: csbi.window.left, y: csbi.window.top} + case 2: + cursor = coord{x: csbi.window.left, y: csbi.window.top} + } + var count, written dword + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + case 'K': + n, err := strconv.Atoi(buf.String()) + if err != nil { + continue + } + var cursor coord + switch n { + case 0: + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + case 1: + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + case 2: + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + } + var count, written dword + count = dword(csbi.size.x - csbi.cursorPosition.x) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + case 'm': + attr := csbi.attributes + cs := buf.String() + if cs == "" { + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) + continue + } + token := strings.Split(cs, ";") + for i := 0; i < len(token); i += 1 { + ns := token[i] + if n, err = strconv.Atoi(ns); err == nil { + switch { + case n == 0 || n == 100: + attr = w.oldattr + case 1 <= n && n <= 5: + attr |= foregroundIntensity + case n == 7: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 22 == n || n == 25 || n == 25: + attr |= foregroundIntensity + case n == 27: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 30 <= n && n <= 37: + attr = (attr & backgroundMask) + if (n-30)&1 != 0 { + attr |= foregroundRed + } + if (n-30)&2 != 0 { + attr |= foregroundGreen + } + if (n-30)&4 != 0 { + attr |= foregroundBlue + } + case n == 38: // set foreground color. + if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256foreAttr == nil { + n256setup() + } + attr &= backgroundMask + attr |= n256foreAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & backgroundMask) + } + case n == 39: // reset foreground color. + attr &= backgroundMask + attr |= w.oldattr & foregroundMask + case 40 <= n && n <= 47: + attr = (attr & foregroundMask) + if (n-40)&1 != 0 { + attr |= backgroundRed + } + if (n-40)&2 != 0 { + attr |= backgroundGreen + } + if (n-40)&4 != 0 { + attr |= backgroundBlue + } + case n == 48: // set background color. + if i < len(token)-2 && token[i+1] == "5" { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256backAttr == nil { + n256setup() + } + attr &= foregroundMask + attr |= n256backAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & foregroundMask) + } + case n == 49: // reset foreground color. + attr &= foregroundMask + attr |= w.oldattr & backgroundMask + case 90 <= n && n <= 97: + attr = (attr & backgroundMask) + attr |= foregroundIntensity + if (n-90)&1 != 0 { + attr |= foregroundRed + } + if (n-90)&2 != 0 { + attr |= foregroundGreen + } + if (n-90)&4 != 0 { + attr |= foregroundBlue + } + case 100 <= n && n <= 107: + attr = (attr & foregroundMask) + attr |= backgroundIntensity + if (n-100)&1 != 0 { + attr |= backgroundRed + } + if (n-100)&2 != 0 { + attr |= backgroundGreen + } + if (n-100)&4 != 0 { + attr |= backgroundBlue + } + } + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + } + } + } + } + return len(data) - w.lastbuf.Len(), nil +} + +type consoleColor struct { + rgb int + red bool + green bool + blue bool + intensity bool +} + +func (c consoleColor) foregroundAttr() (attr word) { + if c.red { + attr |= foregroundRed + } + if c.green { + attr |= foregroundGreen + } + if c.blue { + attr |= foregroundBlue + } + if c.intensity { + attr |= foregroundIntensity + } + return +} + +func (c consoleColor) backgroundAttr() (attr word) { + if c.red { + attr |= backgroundRed + } + if c.green { + attr |= backgroundGreen + } + if c.blue { + attr |= backgroundBlue + } + if c.intensity { + attr |= backgroundIntensity + } + return +} + +var color16 = []consoleColor{ + consoleColor{0x000000, false, false, false, false}, + consoleColor{0x000080, false, false, true, false}, + consoleColor{0x008000, false, true, false, false}, + consoleColor{0x008080, false, true, true, false}, + consoleColor{0x800000, true, false, false, false}, + consoleColor{0x800080, true, false, true, false}, + consoleColor{0x808000, true, true, false, false}, + consoleColor{0xc0c0c0, true, true, true, false}, + consoleColor{0x808080, false, false, false, true}, + consoleColor{0x0000ff, false, false, true, true}, + consoleColor{0x00ff00, false, true, false, true}, + consoleColor{0x00ffff, false, true, true, true}, + consoleColor{0xff0000, true, false, false, true}, + consoleColor{0xff00ff, true, false, true, true}, + consoleColor{0xffff00, true, true, false, true}, + consoleColor{0xffffff, true, true, true, true}, +} + +type hsv struct { + h, s, v float32 +} + +func (a hsv) dist(b hsv) float32 { + dh := a.h - b.h + switch { + case dh > 0.5: + dh = 1 - dh + case dh < -0.5: + dh = -1 - dh + } + ds := a.s - b.s + dv := a.v - b.v + return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) +} + +func toHSV(rgb int) hsv { + r, g, b := float32((rgb&0xFF0000)>>16)/256.0, + float32((rgb&0x00FF00)>>8)/256.0, + float32(rgb&0x0000FF)/256.0 + min, max := minmax3f(r, g, b) + h := max - min + if h > 0 { + if max == r { + h = (g - b) / h + if h < 0 { + h += 6 + } + } else if max == g { + h = 2 + (b-r)/h + } else { + h = 4 + (r-g)/h + } + } + h /= 6.0 + s := max - min + if max != 0 { + s /= max + } + v := max + return hsv{h: h, s: s, v: v} +} + +type hsvTable []hsv + +func toHSVTable(rgbTable []consoleColor) hsvTable { + t := make(hsvTable, len(rgbTable)) + for i, c := range rgbTable { + t[i] = toHSV(c.rgb) + } + return t +} + +func (t hsvTable) find(rgb int) consoleColor { + hsv := toHSV(rgb) + n := 7 + l := float32(5.0) + for i, p := range t { + d := hsv.dist(p) + if d < l { + l, n = d, i + } + } + return color16[n] +} + +func minmax3f(a, b, c float32) (min, max float32) { + if a < b { + if b < c { + return a, c + } else if a < c { + return a, b + } else { + return c, b + } + } else { + if a < c { + return b, c + } else if b < c { + return b, a + } else { + return c, a + } + } +} + +var n256foreAttr []word +var n256backAttr []word + +func n256setup() { + n256foreAttr = make([]word, 256) + n256backAttr = make([]word, 256) + t := toHSVTable(color16) + for i, rgb := range color256 { + c := t.find(rgb) + n256foreAttr[i] = c.foregroundAttr() + n256backAttr[i] = c.backgroundAttr() + } +} diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE new file mode 100644 index 0000000..65dc692 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +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. diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md new file mode 100644 index 0000000..74845de --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/README.md @@ -0,0 +1,37 @@ +# go-isatty + +isatty for golang + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/mattn/go-isatty" + "os" +) + +func main() { + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Println("Is Terminal") + } else { + fmt.Println("Is Not Terminal") + } +} +``` + +## Installation + +``` +$ go get github.com/mattn/go-isatty +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go new file mode 100644 index 0000000..17d4f90 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/doc.go @@ -0,0 +1,2 @@ +// Package isatty implements interface to isatty +package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_appengine.go b/vendor/github.com/mattn/go-isatty/isatty_appengine.go new file mode 100644 index 0000000..83c5887 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_appengine.go @@ -0,0 +1,9 @@ +// +build appengine + +package isatty + +// IsTerminal returns true if the file descriptor is terminal which +// is always false on on appengine classic which is a sandboxed PaaS. +func IsTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go new file mode 100644 index 0000000..98ffe86 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -0,0 +1,18 @@ +// +build darwin freebsd openbsd netbsd +// +build !appengine + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TIOCGETA + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux.go b/vendor/github.com/mattn/go-isatty/isatty_linux.go new file mode 100644 index 0000000..9d24bac --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_linux.go @@ -0,0 +1,18 @@ +// +build linux +// +build !appengine + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TCGETS + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go new file mode 100644 index 0000000..1f0c6bf --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go @@ -0,0 +1,16 @@ +// +build solaris +// +build !appengine + +package isatty + +import ( + "golang.org/x/sys/unix" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c +func IsTerminal(fd uintptr) bool { + var termio unix.Termio + err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) + return err == nil +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go new file mode 100644 index 0000000..83c398b --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -0,0 +1,19 @@ +// +build windows +// +build !appengine + +package isatty + +import ( + "syscall" + "unsafe" +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") +var procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} diff --git a/vendor/github.com/peterh/liner/COPYING b/vendor/github.com/peterh/liner/COPYING new file mode 100644 index 0000000..9e8c9f2 --- /dev/null +++ b/vendor/github.com/peterh/liner/COPYING @@ -0,0 +1,21 @@ +Copyright © 2012 Peter Harris + +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 (including the next +paragraph) 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. + diff --git a/vendor/github.com/peterh/liner/README.md b/vendor/github.com/peterh/liner/README.md new file mode 100644 index 0000000..9148b24 --- /dev/null +++ b/vendor/github.com/peterh/liner/README.md @@ -0,0 +1,100 @@ +Liner +===== + +Liner is a command line editor with history. It was inspired by linenoise; +everything Unix-like is a VT100 (or is trying very hard to be). If your +terminal is not pretending to be a VT100, change it. Liner also support +Windows. + +Liner is released under the X11 license (which is similar to the new BSD +license). + +Line Editing +------------ + +The following line editing commands are supported on platforms and terminals +that Liner supports: + +Keystroke | Action +--------- | ------ +Ctrl-A, Home | Move cursor to beginning of line +Ctrl-E, End | Move cursor to end of line +Ctrl-B, Left | Move cursor one character left +Ctrl-F, Right| Move cursor one character right +Ctrl-Left, Alt-B | Move cursor to previous word +Ctrl-Right, Alt-F | Move cursor to next word +Ctrl-D, Del | (if line is *not* empty) Delete character under cursor +Ctrl-D | (if line *is* empty) End of File - usually quits application +Ctrl-C | Reset input (create new empty prompt) +Ctrl-L | Clear screen (line is unmodified) +Ctrl-T | Transpose previous character with current character +Ctrl-H, BackSpace | Delete character before cursor +Ctrl-W | Delete word leading up to cursor +Ctrl-K | Delete from cursor to end of line +Ctrl-U | Delete from start of line to cursor +Ctrl-P, Up | Previous match from history +Ctrl-N, Down | Next match from history +Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel) +Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead) +Tab | Next completion +Shift-Tab | (after Tab) Previous completion + +Getting started +----------------- + +```go +package main + +import ( + "log" + "os" + "path/filepath" + "strings" + + "github.com/peterh/liner" +) + +var ( + history_fn = filepath.Join(os.TempDir(), ".liner_example_history") + names = []string{"john", "james", "mary", "nancy"} +) + +func main() { + line := liner.NewLiner() + defer line.Close() + + line.SetCtrlCAborts(true) + + line.SetCompleter(func(line string) (c []string) { + for _, n := range names { + if strings.HasPrefix(n, strings.ToLower(line)) { + c = append(c, n) + } + } + return + }) + + if f, err := os.Open(history_fn); err == nil { + line.ReadHistory(f) + f.Close() + } + + if name, err := line.Prompt("What is your name? "); err == nil { + log.Print("Got: ", name) + line.AppendHistory(name) + } else if err == liner.ErrPromptAborted { + log.Print("Aborted") + } else { + log.Print("Error reading line: ", err) + } + + if f, err := os.Create(history_fn); err != nil { + log.Print("Error writing history file: ", err) + } else { + line.WriteHistory(f) + f.Close() + } +} +``` + +For documentation, see http://godoc.org/github.com/peterh/liner diff --git a/vendor/github.com/peterh/liner/bsdinput.go b/vendor/github.com/peterh/liner/bsdinput.go new file mode 100644 index 0000000..3593398 --- /dev/null +++ b/vendor/github.com/peterh/liner/bsdinput.go @@ -0,0 +1,41 @@ +// +build openbsd freebsd netbsd + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]byte + Ispeed int32 + Ospeed int32 +} + +const cursorColumn = false diff --git a/vendor/github.com/peterh/liner/common.go b/vendor/github.com/peterh/liner/common.go new file mode 100644 index 0000000..b6162b6 --- /dev/null +++ b/vendor/github.com/peterh/liner/common.go @@ -0,0 +1,237 @@ +/* +Package liner implements a simple command line editor, inspired by linenoise +(https://github.com/antirez/linenoise/). This package supports WIN32 in +addition to the xterm codes supported by everything else. +*/ +package liner + +import ( + "bufio" + "container/ring" + "errors" + "fmt" + "io" + "strings" + "sync" + "unicode/utf8" +) + +type commonState struct { + terminalSupported bool + outputRedirected bool + inputRedirected bool + history []string + historyMutex sync.RWMutex + completer WordCompleter + columns int + killRing *ring.Ring + ctrlCAborts bool + r *bufio.Reader + tabStyle TabStyle + multiLineMode bool + cursorRows int + maxRows int + shouldRestart ShouldRestart +} + +// TabStyle is used to select how tab completions are displayed. +type TabStyle int + +// Two tab styles are currently available: +// +// TabCircular cycles through each completion item and displays it directly on +// the prompt +// +// TabPrints prints the list of completion items to the screen after a second +// tab key is pressed. This behaves similar to GNU readline and BASH (which +// uses readline) +const ( + TabCircular TabStyle = iota + TabPrints +) + +// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C +// if SetCtrlCAborts(true) has been called on the State +var ErrPromptAborted = errors.New("prompt aborted") + +// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the +// platform is normally supported, but stdout has been redirected +var ErrNotTerminalOutput = errors.New("standard output is not a terminal") + +// Max elements to save on the killring +const KillRingMax = 60 + +// HistoryLimit is the maximum number of entries saved in the scrollback history. +const HistoryLimit = 1000 + +// ReadHistory reads scrollback history from r. Returns the number of lines +// read, and any read error (except io.EOF). +func (s *State) ReadHistory(r io.Reader) (num int, err error) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + in := bufio.NewReader(r) + num = 0 + for { + line, part, err := in.ReadLine() + if err == io.EOF { + break + } + if err != nil { + return num, err + } + if part { + return num, fmt.Errorf("line %d is too long", num+1) + } + if !utf8.Valid(line) { + return num, fmt.Errorf("invalid string at line %d", num+1) + } + num++ + s.history = append(s.history, string(line)) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } + } + return num, nil +} + +// WriteHistory writes scrollback history to w. Returns the number of lines +// successfully written, and any write error. +// +// Unlike the rest of liner's API, WriteHistory is safe to call +// from another goroutine while Prompt is in progress. +// This exception is to facilitate the saving of the history buffer +// during an unexpected exit (for example, due to Ctrl-C being invoked) +func (s *State) WriteHistory(w io.Writer) (num int, err error) { + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + for _, item := range s.history { + _, err := fmt.Fprintln(w, item) + if err != nil { + return num, err + } + num++ + } + return num, nil +} + +// AppendHistory appends an entry to the scrollback history. AppendHistory +// should be called iff Prompt returns a valid command. +func (s *State) AppendHistory(item string) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + if len(s.history) > 0 { + if item == s.history[len(s.history)-1] { + return + } + } + s.history = append(s.history, item) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } +} + +// Returns the history lines starting with prefix +func (s *State) getHistoryByPrefix(prefix string) (ph []string) { + for _, h := range s.history { + if strings.HasPrefix(h, prefix) { + ph = append(ph, h) + } + } + return +} + +// Returns the history lines matching the inteligent search +func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) { + if pattern == "" { + return + } + for _, h := range s.history { + if i := strings.Index(h, pattern); i >= 0 { + ph = append(ph, h) + pos = append(pos, i) + } + } + return +} + +// Completer takes the currently edited line content at the left of the cursor +// and returns a list of completion candidates. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed +// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!". +type Completer func(line string) []string + +// WordCompleter takes the currently edited line with the cursor position and +// returns the completion candidates for the partial word to be completed. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed +// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!". +type WordCompleter func(line string, pos int) (head string, completions []string, tail string) + +// SetCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetCompleter(f Completer) { + if f == nil { + s.completer = nil + return + } + s.completer = func(line string, pos int) (string, []string, string) { + return "", f(string([]rune(line)[:pos])), string([]rune(line)[pos:]) + } +} + +// SetWordCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetWordCompleter(f WordCompleter) { + s.completer = f +} + +// SetTabCompletionStyle sets the behvavior when the Tab key is pressed +// for auto-completion. TabCircular is the default behavior and cycles +// through the list of candidates at the prompt. TabPrints will print +// the available completion candidates to the screen similar to BASH +// and GNU Readline +func (s *State) SetTabCompletionStyle(tabStyle TabStyle) { + s.tabStyle = tabStyle +} + +// ModeApplier is the interface that wraps a representation of the terminal +// mode. ApplyMode sets the terminal to this mode. +type ModeApplier interface { + ApplyMode() error +} + +// SetCtrlCAborts sets whether Prompt on a supported terminal will return an +// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not +// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT +// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts. +func (s *State) SetCtrlCAborts(aborts bool) { + s.ctrlCAborts = aborts +} + +// SetMultiLineMode sets whether line is auto-wrapped. The default is false (single line). +func (s *State) SetMultiLineMode(mlmode bool) { + s.multiLineMode = mlmode +} + +// ShouldRestart is passed the error generated by readNext and returns true if +// the the read should be restarted or false if the error should be returned. +type ShouldRestart func(err error) bool + +// SetShouldRestart sets the restart function that Liner will call to determine +// whether to retry the call to, or return the error returned by, readNext. +func (s *State) SetShouldRestart(f ShouldRestart) { + s.shouldRestart = f +} + +func (s *State) promptUnsupported(p string) (string, error) { + if !s.inputRedirected || !s.terminalSupported { + fmt.Print(p) + } + linebuf, _, err := s.r.ReadLine() + if err != nil { + return "", err + } + return string(linebuf), nil +} diff --git a/vendor/github.com/peterh/liner/fallbackinput.go b/vendor/github.com/peterh/liner/fallbackinput.go new file mode 100644 index 0000000..d9eb79d --- /dev/null +++ b/vendor/github.com/peterh/liner/fallbackinput.go @@ -0,0 +1,57 @@ +// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd + +package liner + +import ( + "bufio" + "errors" + "os" +) + +// State represents an open terminal +type State struct { + commonState +} + +// Prompt displays p, and then waits for user input. Prompt does not support +// line editing on this operating system. +func (s *State) Prompt(p string) (string, error) { + return s.promptUnsupported(p) +} + +// PasswordPrompt is not supported in this OS. +func (s *State) PasswordPrompt(p string) (string, error) { + return "", errors.New("liner: function not supported in this terminal") +} + +// NewLiner initializes a new *State +// +// Note that this operating system uses a fallback mode without line +// editing. Patches welcome. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + return &s +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + return nil +} + +// TerminalSupported returns false because line editing is not +// supported on this platform. +func TerminalSupported() bool { + return false +} + +type noopMode struct{} + +func (n noopMode) ApplyMode() error { + return nil +} + +// TerminalMode returns a noop InputModeSetter on this platform. +func TerminalMode() (ModeApplier, error) { + return noopMode{}, nil +} diff --git a/vendor/github.com/peterh/liner/input.go b/vendor/github.com/peterh/liner/input.go new file mode 100644 index 0000000..0ee6be7 --- /dev/null +++ b/vendor/github.com/peterh/liner/input.go @@ -0,0 +1,367 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "bufio" + "errors" + "os" + "os/signal" + "strconv" + "strings" + "syscall" + "time" +) + +type nexter struct { + r rune + err error +} + +// State represents an open terminal +type State struct { + commonState + origMode termios + defaultMode termios + next <-chan nexter + winch chan os.Signal + pending []rune + useCHA bool +} + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +// +// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will +// leak a channel every time you call it. Therefore, it is recommened that you +// upgrade to a newer release of Go, or ensure that NewLiner is only called +// once. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + + s.terminalSupported = TerminalSupported() + if m, err := TerminalMode(); err == nil { + s.origMode = *m.(*termios) + } else { + s.inputRedirected = true + } + if _, err := getMode(syscall.Stdout); err != 0 { + s.outputRedirected = true + } + if s.inputRedirected && s.outputRedirected { + s.terminalSupported = false + } + if s.terminalSupported && !s.inputRedirected && !s.outputRedirected { + mode := s.origMode + mode.Iflag &^= icrnl | inpck | istrip | ixon + mode.Cflag |= cs8 + mode.Lflag &^= syscall.ECHO | icanon | iexten + mode.ApplyMode() + + winch := make(chan os.Signal, 1) + signal.Notify(winch, syscall.SIGWINCH) + s.winch = winch + + s.checkOutput() + } + + if !s.outputRedirected { + s.outputRedirected = !s.getColumns() + } + + return &s +} + +var errTimedOut = errors.New("timeout") + +func (s *State) startPrompt() { + if s.terminalSupported { + if m, err := TerminalMode(); err == nil { + s.defaultMode = *m.(*termios) + mode := s.defaultMode + mode.Lflag &^= isig + mode.ApplyMode() + } + } + s.restartPrompt() +} + +func (s *State) restartPrompt() { + next := make(chan nexter) + go func() { + for { + var n nexter + n.r, _, n.err = s.r.ReadRune() + next <- n + // Shut down nexter loop when an end condition has been reached + if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD { + close(next) + return + } + } + }() + s.next = next +} + +func (s *State) stopPrompt() { + if s.terminalSupported { + s.defaultMode.ApplyMode() + } +} + +func (s *State) nextPending(timeout <-chan time.Time) (rune, error) { + select { + case thing, ok := <-s.next: + if !ok { + return 0, errors.New("liner: internal error") + } + if thing.err != nil { + return 0, thing.err + } + s.pending = append(s.pending, thing.r) + return thing.r, nil + case <-timeout: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, errTimedOut + } + // not reached + return 0, nil +} + +func (s *State) readNext() (interface{}, error) { + if len(s.pending) > 0 { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + var r rune + select { + case thing, ok := <-s.next: + if !ok { + return 0, errors.New("liner: internal error") + } + if thing.err != nil { + return nil, thing.err + } + r = thing.r + case <-s.winch: + s.getColumns() + return winch, nil + } + if r != esc { + return r, nil + } + s.pending = append(s.pending, r) + + // Wait at most 50 ms for the rest of the escape sequence + // If nothing else arrives, it was an actual press of the esc key + timeout := time.After(50 * time.Millisecond) + flag, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return flag, nil + } + return unknown, err + } + + switch flag { + case '[': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return unknown, err + } + switch code { + case 'A': + s.pending = s.pending[:0] // escape code complete + return up, nil + case 'B': + s.pending = s.pending[:0] // escape code complete + return down, nil + case 'C': + s.pending = s.pending[:0] // escape code complete + return right, nil + case 'D': + s.pending = s.pending[:0] // escape code complete + return left, nil + case 'F': + s.pending = s.pending[:0] // escape code complete + return end, nil + case 'H': + s.pending = s.pending[:0] // escape code complete + return home, nil + case 'Z': + s.pending = s.pending[:0] // escape code complete + return shiftTab, nil + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num := []rune{code} + for { + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case ';': + // Modifier code to follow + // This only supports Ctrl-left and Ctrl-right for now + x, _ := strconv.ParseInt(string(num), 10, 32) + if x != 1 { + // Can't be left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + num = num[:0] + for { + code, err = s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case 'C', 'D': + // right, left + mod, _ := strconv.ParseInt(string(num), 10, 32) + if mod != 5 { + // Not bare Ctrl + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + s.pending = s.pending[:0] // escape code complete + if code == 'C' { + return wordRight, nil + } + return wordLeft, nil + default: + // Not left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + case '~': + s.pending = s.pending[:0] // escape code complete + x, _ := strconv.ParseInt(string(num), 10, 32) + switch x { + case 2: + return insert, nil + case 3: + return del, nil + case 5: + return pageUp, nil + case 6: + return pageDown, nil + case 7: + return home, nil + case 8: + return end, nil + case 15: + return f5, nil + case 17: + return f6, nil + case 18: + return f7, nil + case 19: + return f8, nil + case 20: + return f9, nil + case 21: + return f10, nil + case 23: + return f11, nil + case 24: + return f12, nil + default: + return unknown, nil + } + default: + // unrecognized escape code + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + } + + case 'O': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + s.pending = s.pending[:0] // escape code complete + switch code { + case 'c': + return wordRight, nil + case 'd': + return wordLeft, nil + case 'H': + return home, nil + case 'F': + return end, nil + case 'P': + return f1, nil + case 'Q': + return f2, nil + case 'R': + return f3, nil + case 'S': + return f4, nil + default: + return unknown, nil + } + case 'b': + s.pending = s.pending[:0] // escape code complete + return altB, nil + case 'f': + s.pending = s.pending[:0] // escape code complete + return altF, nil + case 'y': + s.pending = s.pending[:0] // escape code complete + return altY, nil + default: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + + // not reached + return r, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + stopSignal(s.winch) + if !s.inputRedirected { + s.origMode.ApplyMode() + } + return nil +} + +// TerminalSupported returns true if the current terminal supports +// line editing features, and false if liner will use the 'dumb' +// fallback for input. +// Note that TerminalSupported does not check all factors that may +// cause liner to not fully support the terminal (such as stdin redirection) +func TerminalSupported() bool { + bad := map[string]bool{"": true, "dumb": true, "cons25": true} + return !bad[strings.ToLower(os.Getenv("TERM"))] +} diff --git a/vendor/github.com/peterh/liner/input_darwin.go b/vendor/github.com/peterh/liner/input_darwin.go new file mode 100644 index 0000000..e98ab4a --- /dev/null +++ b/vendor/github.com/peterh/liner/input_darwin.go @@ -0,0 +1,43 @@ +// +build darwin + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uintptr + Oflag uintptr + Cflag uintptr + Lflag uintptr + Cc [20]byte + Ispeed uintptr + Ospeed uintptr +} + +// Terminal.app needs a column for the cursor when the input line is at the +// bottom of the window. +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/input_linux.go b/vendor/github.com/peterh/liner/input_linux.go new file mode 100644 index 0000000..56ed185 --- /dev/null +++ b/vendor/github.com/peterh/liner/input_linux.go @@ -0,0 +1,28 @@ +// +build linux + +package liner + +import "syscall" + +const ( + getTermios = syscall.TCGETS + setTermios = syscall.TCSETS +) + +const ( + icrnl = syscall.ICRNL + inpck = syscall.INPCK + istrip = syscall.ISTRIP + ixon = syscall.IXON + opost = syscall.OPOST + cs8 = syscall.CS8 + isig = syscall.ISIG + icanon = syscall.ICANON + iexten = syscall.IEXTEN +) + +type termios struct { + syscall.Termios +} + +const cursorColumn = false diff --git a/vendor/github.com/peterh/liner/input_windows.go b/vendor/github.com/peterh/liner/input_windows.go new file mode 100644 index 0000000..199b942 --- /dev/null +++ b/vendor/github.com/peterh/liner/input_windows.go @@ -0,0 +1,324 @@ +package liner + +import ( + "bufio" + "os" + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") +) + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + std_input_handle = uint32(-10 & 0xFFFFFFFF) + std_output_handle = uint32(-11 & 0xFFFFFFFF) + std_error_handle = uint32(-12 & 0xFFFFFFFF) + invalid_handle_value = ^uintptr(0) +) + +type inputMode uint32 + +// State represents an open terminal +type State struct { + commonState + handle syscall.Handle + hOut syscall.Handle + origMode inputMode + defaultMode inputMode + key interface{} + repeat uint16 +} + +const ( + enableEchoInput = 0x4 + enableInsertMode = 0x20 + enableLineInput = 0x2 + enableMouseInput = 0x10 + enableProcessedInput = 0x1 + enableQuickEditMode = 0x40 + enableWindowInput = 0x8 +) + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +func NewLiner() *State { + var s State + hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle)) + s.handle = syscall.Handle(hIn) + hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle)) + s.hOut = syscall.Handle(hOut) + + s.terminalSupported = true + if m, err := TerminalMode(); err == nil { + s.origMode = m.(inputMode) + mode := s.origMode + mode &^= enableEchoInput + mode &^= enableInsertMode + mode &^= enableLineInput + mode &^= enableMouseInput + mode |= enableWindowInput + mode.ApplyMode() + } else { + s.inputRedirected = true + s.r = bufio.NewReader(os.Stdin) + } + + s.getColumns() + s.outputRedirected = s.columns <= 0 + + return &s +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + focus_event = 0x0010 + key_event = 0x0001 + menu_event = 0x0008 + mouse_event = 0x0002 + window_buffer_size_event = 0x0004 +) + +type input_record struct { + eventType uint16 + pad uint16 + blob [16]byte +} + +type key_event_record struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + Char int16 + ControlKeyState uint32 +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + vk_tab = 0x09 + vk_prior = 0x21 + vk_next = 0x22 + vk_end = 0x23 + vk_home = 0x24 + vk_left = 0x25 + vk_up = 0x26 + vk_right = 0x27 + vk_down = 0x28 + vk_insert = 0x2d + vk_delete = 0x2e + vk_f1 = 0x70 + vk_f2 = 0x71 + vk_f3 = 0x72 + vk_f4 = 0x73 + vk_f5 = 0x74 + vk_f6 = 0x75 + vk_f7 = 0x76 + vk_f8 = 0x77 + vk_f9 = 0x78 + vk_f10 = 0x79 + vk_f11 = 0x7a + vk_f12 = 0x7b + bKey = 0x42 + fKey = 0x46 + yKey = 0x59 +) + +const ( + shiftPressed = 0x0010 + leftAltPressed = 0x0002 + leftCtrlPressed = 0x0008 + rightAltPressed = 0x0001 + rightCtrlPressed = 0x0004 + + modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed +) + +func (s *State) readNext() (interface{}, error) { + if s.repeat > 0 { + s.repeat-- + return s.key, nil + } + + var input input_record + pbuf := uintptr(unsafe.Pointer(&input)) + var rv uint32 + prv := uintptr(unsafe.Pointer(&rv)) + + for { + ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) + + if ok == 0 { + return nil, err + } + + if input.eventType == window_buffer_size_event { + xy := (*coord)(unsafe.Pointer(&input.blob[0])) + s.columns = int(xy.x) + if s.columns > 1 { + s.columns-- + } + return winch, nil + } + if input.eventType != key_event { + continue + } + ke := (*key_event_record)(unsafe.Pointer(&input.blob[0])) + if ke.KeyDown == 0 { + continue + } + + if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed { + s.key = shiftTab + } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altB + } else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altF + } else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altY + } else if ke.Char > 0 { + s.key = rune(ke.Char) + } else { + switch ke.VirtualKeyCode { + case vk_prior: + s.key = pageUp + case vk_next: + s.key = pageDown + case vk_end: + s.key = end + case vk_home: + s.key = home + case vk_left: + s.key = left + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordLeft + } + } + case vk_right: + s.key = right + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordRight + } + } + case vk_up: + s.key = up + case vk_down: + s.key = down + case vk_insert: + s.key = insert + case vk_delete: + s.key = del + case vk_f1: + s.key = f1 + case vk_f2: + s.key = f2 + case vk_f3: + s.key = f3 + case vk_f4: + s.key = f4 + case vk_f5: + s.key = f5 + case vk_f6: + s.key = f6 + case vk_f7: + s.key = f7 + case vk_f8: + s.key = f8 + case vk_f9: + s.key = f9 + case vk_f10: + s.key = f10 + case vk_f11: + s.key = f11 + case vk_f12: + s.key = f12 + default: + // Eat modifier keys + // TODO: return Action(Unknown) if the key isn't a + // modifier. + continue + } + } + + if ke.RepeatCount > 1 { + s.repeat = ke.RepeatCount - 1 + } + return s.key, nil + } + return unknown, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + s.origMode.ApplyMode() + return nil +} + +func (s *State) startPrompt() { + if m, err := TerminalMode(); err == nil { + s.defaultMode = m.(inputMode) + mode := s.defaultMode + mode &^= enableProcessedInput + mode.ApplyMode() + } +} + +func (s *State) restartPrompt() { +} + +func (s *State) stopPrompt() { + s.defaultMode.ApplyMode() +} + +// TerminalSupported returns true because line editing is always +// supported on Windows. +func TerminalSupported() bool { + return true +} + +func (mode inputMode) ApplyMode() error { + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return err + } + ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode)) + if ok != 0 { + err = nil + } + return err +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + var mode inputMode + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return nil, err + } + ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode))) + if ok != 0 { + err = nil + } + return mode, err +} diff --git a/vendor/github.com/peterh/liner/line.go b/vendor/github.com/peterh/liner/line.go new file mode 100644 index 0000000..903dd24 --- /dev/null +++ b/vendor/github.com/peterh/liner/line.go @@ -0,0 +1,1033 @@ +// +build windows linux darwin openbsd freebsd netbsd + +package liner + +import ( + "container/ring" + "errors" + "fmt" + "io" + "strings" + "unicode" + "unicode/utf8" +) + +type action int + +const ( + left action = iota + right + up + down + home + end + insert + del + pageUp + pageDown + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + altB + altF + altY + shiftTab + wordLeft + wordRight + winch + unknown +) + +const ( + ctrlA = 1 + ctrlB = 2 + ctrlC = 3 + ctrlD = 4 + ctrlE = 5 + ctrlF = 6 + ctrlG = 7 + ctrlH = 8 + tab = 9 + lf = 10 + ctrlK = 11 + ctrlL = 12 + cr = 13 + ctrlN = 14 + ctrlO = 15 + ctrlP = 16 + ctrlQ = 17 + ctrlR = 18 + ctrlS = 19 + ctrlT = 20 + ctrlU = 21 + ctrlV = 22 + ctrlW = 23 + ctrlX = 24 + ctrlY = 25 + ctrlZ = 26 + esc = 27 + bs = 127 +) + +const ( + beep = "\a" +) + +type tabDirection int + +const ( + tabForward tabDirection = iota + tabReverse +) + +func (s *State) refresh(prompt []rune, buf []rune, pos int) error { + if s.multiLineMode { + return s.refreshMultiLine(prompt, buf, pos) + } else { + return s.refreshSingleLine(prompt, buf, pos) + } +} + +func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error { + s.cursorPos(0) + _, err := fmt.Print(string(prompt)) + if err != nil { + return err + } + + pLen := countGlyphs(prompt) + bLen := countGlyphs(buf) + pos = countGlyphs(buf[:pos]) + if pLen+bLen < s.columns { + _, err = fmt.Print(string(buf)) + s.eraseLine() + s.cursorPos(pLen + pos) + } else { + // Find space available + space := s.columns - pLen + space-- // space for cursor + start := pos - space/2 + end := start + space + if end > bLen { + end = bLen + start = end - space + } + if start < 0 { + start = 0 + end = space + } + pos -= start + + // Leave space for markers + if start > 0 { + start++ + } + if end < bLen { + end-- + } + startRune := len(getPrefixGlyphs(buf, start)) + line := getPrefixGlyphs(buf[startRune:], end-start) + + // Output + if start > 0 { + fmt.Print("{") + } + fmt.Print(string(line)) + if end < bLen { + fmt.Print("}") + } + + // Set cursor position + s.eraseLine() + s.cursorPos(pLen + pos) + } + return err +} + +func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error { + promptColumns := countMultiLineGlyphs(prompt, s.columns, 0) + totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns) + totalRows := (totalColumns + s.columns - 1) / s.columns + maxRows := s.maxRows + if totalRows > s.maxRows { + s.maxRows = totalRows + } + cursorRows := s.cursorRows + if cursorRows == 0 { + cursorRows = 1 + } + + /* First step: clear all the lines used before. To do so start by + * going to the last row. */ + if maxRows-cursorRows > 0 { + s.moveDown(maxRows - cursorRows) + } + + /* Now for every row clear it, go up. */ + for i := 0; i < maxRows-1; i++ { + s.cursorPos(0) + s.eraseLine() + s.moveUp(1) + } + + /* Clean the top line. */ + s.cursorPos(0) + s.eraseLine() + + /* Write the prompt and the current buffer content */ + if _, err := fmt.Print(string(prompt)); err != nil { + return err + } + if _, err := fmt.Print(string(buf)); err != nil { + return err + } + + /* If we are at the very end of the screen with our prompt, we need to + * emit a newline and move the prompt to the first column. */ + cursorColumns := countMultiLineGlyphs(buf[:pos], s.columns, promptColumns) + if cursorColumns == totalColumns && totalColumns%s.columns == 0 { + s.emitNewLine() + s.cursorPos(0) + totalRows++ + if totalRows > s.maxRows { + s.maxRows = totalRows + } + } + + /* Move cursor to right position. */ + cursorRows = (cursorColumns + s.columns) / s.columns + if s.cursorRows > 0 && totalRows-cursorRows > 0 { + s.moveUp(totalRows - cursorRows) + } + /* Set column. */ + s.cursorPos(cursorColumns % s.columns) + + s.cursorRows = cursorRows + return nil +} + +func (s *State) resetMultiLine(prompt []rune, buf []rune, pos int) { + columns := countMultiLineGlyphs(prompt, s.columns, 0) + columns = countMultiLineGlyphs(buf[:pos], s.columns, columns) + columns += 2 // ^C + cursorRows := (columns + s.columns) / s.columns + if s.maxRows-cursorRows > 0 { + for i := 0; i < s.maxRows-cursorRows; i++ { + fmt.Println() // always moves the cursor down or scrolls the window up as needed + } + } + s.maxRows = 1 + s.cursorRows = 0 +} + +func longestCommonPrefix(strs []string) string { + if len(strs) == 0 { + return "" + } + longest := strs[0] + + for _, str := range strs[1:] { + for !strings.HasPrefix(str, longest) { + longest = longest[:len(longest)-1] + } + } + // Remove trailing partial runes + longest = strings.TrimRight(longest, "\uFFFD") + return longest +} + +func (s *State) circularTabs(items []string) func(tabDirection) (string, error) { + item := -1 + return func(direction tabDirection) (string, error) { + if direction == tabForward { + if item < len(items)-1 { + item++ + } else { + item = 0 + } + } else if direction == tabReverse { + if item > 0 { + item-- + } else { + item = len(items) - 1 + } + } + return items[item], nil + } +} + +func calculateColumns(screenWidth int, items []string) (numColumns, numRows, maxWidth int) { + for _, item := range items { + if len(item) >= screenWidth { + return 1, len(items), screenWidth - 1 + } + if len(item) >= maxWidth { + maxWidth = len(item) + 1 + } + } + + numColumns = screenWidth / maxWidth + numRows = len(items) / numColumns + if len(items)%numColumns > 0 { + numRows++ + } + + if len(items) <= numColumns { + maxWidth = 0 + } + + return +} + +func (s *State) printedTabs(items []string) func(tabDirection) (string, error) { + numTabs := 1 + prefix := longestCommonPrefix(items) + return func(direction tabDirection) (string, error) { + if len(items) == 1 { + return items[0], nil + } + + if numTabs == 2 { + if len(items) > 100 { + fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items)) + prompt: + for { + next, err := s.readNext() + if err != nil { + return prefix, err + } + + if key, ok := next.(rune); ok { + switch key { + case 'n', 'N': + return prefix, nil + case 'y', 'Y': + break prompt + case ctrlC, ctrlD, cr, lf: + s.restartPrompt() + } + } + } + } + fmt.Println("") + + numColumns, numRows, maxWidth := calculateColumns(s.columns, items) + + for i := 0; i < numRows; i++ { + for j := 0; j < numColumns*numRows; j += numRows { + if i+j < len(items) { + if maxWidth > 0 { + fmt.Printf("%-*.[1]*s", maxWidth, items[i+j]) + } else { + fmt.Printf("%v ", items[i+j]) + } + } + } + fmt.Println("") + } + } else { + numTabs++ + } + return prefix, nil + } +} + +func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) { + if s.completer == nil { + return line, pos, rune(esc), nil + } + head, list, tail := s.completer(string(line), pos) + if len(list) <= 0 { + return line, pos, rune(esc), nil + } + hl := utf8.RuneCountInString(head) + if len(list) == 1 { + s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0])) + return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil + } + + direction := tabForward + tabPrinter := s.circularTabs(list) + if s.tabStyle == TabPrints { + tabPrinter = s.printedTabs(list) + } + + for { + pick, err := tabPrinter(direction) + if err != nil { + return line, pos, rune(esc), err + } + s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick)) + + next, err := s.readNext() + if err != nil { + return line, pos, rune(esc), err + } + if key, ok := next.(rune); ok { + if key == tab { + direction = tabForward + continue + } + if key == esc { + return line, pos, rune(esc), nil + } + } + if a, ok := next.(action); ok && a == shiftTab { + direction = tabReverse + continue + } + return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil + } + // Not reached + return line, pos, rune(esc), nil +} + +// reverse intelligent search, implements a bash-like history search. +func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) { + p := "(reverse-i-search)`': " + s.refresh([]rune(p), origLine, origPos) + + line := []rune{} + pos := 0 + foundLine := string(origLine) + foundPos := origPos + + getLine := func() ([]rune, []rune, int) { + search := string(line) + prompt := "(reverse-i-search)`%s': " + return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos + } + + history, positions := s.getHistoryByPattern(string(line)) + historyPos := len(history) - 1 + + for { + next, err := s.readNext() + if err != nil { + return []rune(foundLine), foundPos, rune(esc), err + } + + switch v := next.(type) { + case rune: + switch v { + case ctrlR: // Search backwards + if historyPos > 0 && historyPos < len(history) { + historyPos-- + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlS: // Search forward + if historyPos < len(history)-1 && historyPos >= 0 { + historyPos++ + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + + // For each char deleted, display the last matching line of history + history, positions := s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case ctrlG: // Cancel + return origLine, origPos, rune(esc), err + + case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK, + ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + case 0, ctrlC, esc, 28, 29, 30, 31: + return []rune(foundLine), foundPos, next, err + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + + // For each keystroke typed, display the last matching line of history + history, positions = s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case action: + return []rune(foundLine), foundPos, next, err + } + s.refresh(getLine()) + } +} + +// addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a +// new node in the end of the kill ring, and move the current pointer to the new +// node. If mode is 1 or 2 it appends or prepends the text to the current entry +// of the killRing. +func (s *State) addToKillRing(text []rune, mode int) { + // Don't use the same underlying array as text + killLine := make([]rune, len(text)) + copy(killLine, text) + + // Point killRing to a newNode, procedure depends on the killring state and + // append mode. + if mode == 0 { // Add new node to killRing + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + } else if s.killRing.Len() >= KillRingMax { // if killring is "full" + s.killRing = s.killRing.Next() + } else { // Normal case + s.killRing.Link(ring.New(1)) + s.killRing = s.killRing.Next() + } + } else { + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + s.killRing.Value = []rune{} + } + if mode == 1 { // Append to last entry + killLine = append(s.killRing.Value.([]rune), killLine...) + } else if mode == 2 { // Prepend to last entry + killLine = append(killLine, s.killRing.Value.([]rune)...) + } + } + + // Save text in the current killring node + s.killRing.Value = killLine +} + +func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) { + if s.killRing == nil { + return text, pos, rune(esc), nil + } + + lineStart := text[:pos] + lineEnd := text[pos:] + var line []rune + + for { + value := s.killRing.Value.([]rune) + line = make([]rune, 0) + line = append(line, lineStart...) + line = append(line, value...) + line = append(line, lineEnd...) + + pos = len(lineStart) + len(value) + s.refresh(p, line, pos) + + next, err := s.readNext() + if err != nil { + return line, pos, next, err + } + + switch v := next.(type) { + case rune: + return line, pos, next, nil + case action: + switch v { + case altY: + s.killRing = s.killRing.Prev() + default: + return line, pos, next, nil + } + } + } + + return line, pos, esc, nil +} + +// Prompt displays p and returns a line of user input, not including a trailing +// newline character. An io.EOF error is returned if the user signals end-of-file +// by pressing Ctrl-D. Prompt allows line editing if the terminal supports it. +func (s *State) Prompt(prompt string) (string, error) { + return s.PromptWithSuggestion(prompt, "", 0) +} + +// PromptWithSuggestion displays prompt and an editable text with cursor at +// given position. The cursor will be set to the end of the line if given position +// is negative or greater than length of text. Returns a line of user input, not +// including a trailing newline character. An io.EOF error is returned if the user +// signals end-of-file by pressing Ctrl-D. +func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) { + if s.inputRedirected || !s.terminalSupported { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + fmt.Print(prompt) + p := []rune(prompt) + var line = []rune(text) + historyEnd := "" + prefixHistory := s.getHistoryByPrefix(string(line)) + historyPos := len(prefixHistory) + historyAction := false // used to mark history related actions + killAction := 0 // used to mark kill related actions + + defer s.stopPrompt() + + if pos < 0 || len(text) < pos { + pos = len(text) + } + if len(line) > 0 { + s.refresh(p, line, pos) + } + +restart: + s.startPrompt() + s.getColumns() + +mainLoop: + for { + next, err := s.readNext() + haveNext: + if err != nil { + if s.shouldRestart != nil && s.shouldRestart(err) { + goto restart + } + return "", err + } + + historyAction = false + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + fmt.Println() + break mainLoop + case ctrlA: // Start of line + pos = 0 + s.refresh(p, line, pos) + case ctrlE: // End of line + pos = len(line) + s.refresh(p, line, pos) + case ctrlB: // left + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlF: // right + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + s.refresh(p, line, pos) + } + case ctrlK: // delete remainder of line + if pos >= len(line) { + fmt.Print(beep) + } else { + if killAction > 0 { + s.addToKillRing(line[pos:], 1) // Add in apend mode + } else { + s.addToKillRing(line[pos:], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was a kill action + line = line[:pos] + s.refresh(p, line, pos) + } + case ctrlP: // up + historyAction = true + if historyPos > 0 { + if historyPos == len(prefixHistory) { + historyEnd = string(line) + } + historyPos-- + line = []rune(prefixHistory[historyPos]) + pos = len(line) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlN: // down + historyAction = true + if historyPos < len(prefixHistory) { + historyPos++ + if historyPos == len(prefixHistory) { + line = []rune(historyEnd) + } else { + line = []rune(prefixHistory[historyPos]) + } + pos = len(line) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlT: // transpose prev glyph with glyph under cursor + if len(line) < 2 || pos < 1 { + fmt.Print(beep) + } else { + if pos == len(line) { + pos -= len(getSuffixGlyphs(line, 1)) + } + prev := getSuffixGlyphs(line[:pos], 1) + next := getPrefixGlyphs(line[pos:], 1) + scratch := make([]rune, len(prev)) + copy(scratch, prev) + copy(line[pos-len(prev):], next) + copy(line[pos-len(prev)+len(next):], scratch) + pos += len(next) + s.refresh(p, line, pos) + } + case ctrlL: // clear screen + s.eraseScreen() + s.refresh(p, line, pos) + case ctrlC: // reset + fmt.Println("^C") + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + s.refresh(p, line, pos) + } + case ctrlU: // Erase line before cursor + if killAction > 0 { + s.addToKillRing(line[:pos], 2) // Add in prepend mode + } else { + s.addToKillRing(line[:pos], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was some killing + line = line[pos:] + pos = 0 + s.refresh(p, line, pos) + case ctrlW: // Erase word + if pos == 0 { + fmt.Print(beep) + break + } + // Remove whitespace to the left + var buf []rune // Store the deleted chars in a buffer + for { + if pos == 0 || !unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Remove non-whitespace to the left + for { + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Invert the buffer and save the result on the killRing + var newBuf []rune + for i := len(buf) - 1; i >= 0; i-- { + newBuf = append(newBuf, buf[i]) + } + if killAction > 0 { + s.addToKillRing(newBuf, 2) // Add in prepend mode + } else { + s.addToKillRing(newBuf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing + + s.refresh(p, line, pos) + case ctrlY: // Paste from Yank buffer + line, pos, next, err = s.yank(p, line, pos) + goto haveNext + case ctrlR: // Reverse Search + line, pos, next, err = s.reverseISearch(line, pos) + s.refresh(p, line, pos) + goto haveNext + case tab: // Tab completion + line, pos, next, err = s.tabComplete(p, line, pos) + goto haveNext + // Catch keys that do nothing, but you don't want them to beep + case esc: + // DO NOTHING + // Unused keys + case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + if pos == len(line) && !s.multiLineMode && countGlyphs(p)+countGlyphs(line) < s.columns-1 { + line = append(line, v) + fmt.Printf("%c", v) + pos++ + } else { + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + s.refresh(p, line, pos) + } + } + case action: + switch v { + case del: + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + } + case left: + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + } else { + fmt.Print(beep) + } + case wordLeft, altB: + if pos > 0 { + var spaceHere, spaceLeft, leftKnown bool + for { + pos-- + if pos == 0 { + break + } + if leftKnown { + spaceHere = spaceLeft + } else { + spaceHere = unicode.IsSpace(line[pos]) + } + spaceLeft, leftKnown = unicode.IsSpace(line[pos-1]), true + if !spaceHere && spaceLeft { + break + } + } + } else { + fmt.Print(beep) + } + case right: + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + } else { + fmt.Print(beep) + } + case wordRight, altF: + if pos < len(line) { + var spaceHere, spaceLeft, hereKnown bool + for { + pos++ + if pos == len(line) { + break + } + if hereKnown { + spaceLeft = spaceHere + } else { + spaceLeft = unicode.IsSpace(line[pos-1]) + } + spaceHere, hereKnown = unicode.IsSpace(line[pos]), true + if spaceHere && !spaceLeft { + break + } + } + } else { + fmt.Print(beep) + } + case up: + historyAction = true + if historyPos > 0 { + if historyPos == len(prefixHistory) { + historyEnd = string(line) + } + historyPos-- + line = []rune(prefixHistory[historyPos]) + pos = len(line) + } else { + fmt.Print(beep) + } + case down: + historyAction = true + if historyPos < len(prefixHistory) { + historyPos++ + if historyPos == len(prefixHistory) { + line = []rune(historyEnd) + } else { + line = []rune(prefixHistory[historyPos]) + } + pos = len(line) + } else { + fmt.Print(beep) + } + case home: // Start of line + pos = 0 + case end: // End of line + pos = len(line) + case winch: // Window change + if s.multiLineMode { + if s.maxRows-s.cursorRows > 0 { + s.moveDown(s.maxRows - s.cursorRows) + } + for i := 0; i < s.maxRows-1; i++ { + s.cursorPos(0) + s.eraseLine() + s.moveUp(1) + } + s.maxRows = 1 + s.cursorRows = 1 + } + } + s.refresh(p, line, pos) + } + if !historyAction { + prefixHistory = s.getHistoryByPrefix(string(line)) + historyPos = len(prefixHistory) + } + if killAction > 0 { + killAction-- + } + } + return string(line), nil +} + +// PasswordPrompt displays p, and then waits for user input. The input typed by +// the user is not displayed in the terminal. +func (s *State) PasswordPrompt(prompt string) (string, error) { + if !s.terminalSupported { + return "", errors.New("liner: function not supported in this terminal") + } + if s.inputRedirected { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + + defer s.stopPrompt() + +restart: + s.startPrompt() + s.getColumns() + + fmt.Print(prompt) + p := []rune(prompt) + var line []rune + pos := 0 + +mainLoop: + for { + next, err := s.readNext() + if err != nil { + if s.shouldRestart != nil && s.shouldRestart(err) { + goto restart + } + return "", err + } + + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + fmt.Println() + break mainLoop + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + case ctrlL: // clear screen + s.eraseScreen() + s.refresh(p, []rune{}, 0) + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + } + case ctrlC: + fmt.Println("^C") + if s.multiLineMode { + s.resetMultiLine(p, line, pos) + } + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + // Unused keys + case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, + ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + } + } + } + return string(line), nil +} diff --git a/vendor/github.com/peterh/liner/output.go b/vendor/github.com/peterh/liner/output.go new file mode 100644 index 0000000..6d83d4e --- /dev/null +++ b/vendor/github.com/peterh/liner/output.go @@ -0,0 +1,79 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "fmt" + "os" + "strings" + "syscall" + "unsafe" +) + +func (s *State) cursorPos(x int) { + if s.useCHA { + // 'G' is "Cursor Character Absolute (CHA)" + fmt.Printf("\x1b[%dG", x+1) + } else { + // 'C' is "Cursor Forward (CUF)" + fmt.Print("\r") + if x > 0 { + fmt.Printf("\x1b[%dC", x) + } + } +} + +func (s *State) eraseLine() { + fmt.Print("\x1b[0K") +} + +func (s *State) eraseScreen() { + fmt.Print("\x1b[H\x1b[2J") +} + +func (s *State) moveUp(lines int) { + fmt.Printf("\x1b[%dA", lines) +} + +func (s *State) moveDown(lines int) { + fmt.Printf("\x1b[%dB", lines) +} + +func (s *State) emitNewLine() { + fmt.Print("\n") +} + +type winSize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func (s *State) getColumns() bool { + var ws winSize + ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout), + syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))) + if int(ok) < 0 { + return false + } + s.columns = int(ws.col) + if cursorColumn && s.columns > 1 { + s.columns-- + } + return true +} + +func (s *State) checkOutput() { + // xterm is known to support CHA + if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") { + s.useCHA = true + return + } + + // The test for functional ANSI CHA is unreliable (eg the Windows + // telnet command does not support reading the cursor position with + // an ANSI DSR request, despite setting TERM=ansi) + + // Assume CHA isn't supported (which should be safe, although it + // does result in occasional visible cursor jitter) + s.useCHA = false +} diff --git a/vendor/github.com/peterh/liner/output_windows.go b/vendor/github.com/peterh/liner/output_windows.go new file mode 100644 index 0000000..63c9c5d --- /dev/null +++ b/vendor/github.com/peterh/liner/output_windows.go @@ -0,0 +1,76 @@ +package liner + +import ( + "unsafe" +) + +type coord struct { + x, y int16 +} +type smallRect struct { + left, top, right, bottom int16 +} + +type consoleScreenBufferInfo struct { + dwSize coord + dwCursorPosition coord + wAttributes int16 + srWindow smallRect + dwMaximumWindowSize coord +} + +func (s *State) cursorPos(x int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16)) +} + +func (s *State) eraseLine() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16), + uintptr(unsafe.Pointer(&numWritten))) +} + +func (s *State) eraseScreen() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y), + 0, + uintptr(unsafe.Pointer(&numWritten))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0) +} + +func (s *State) moveUp(lines int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)-lines)<<16)) +} + +func (s *State) moveDown(lines int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)+lines)<<16)) +} + +func (s *State) emitNewLine() { + // windows doesn't need to omit a new line +} + +func (s *State) getColumns() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + s.columns = int(sbi.dwSize.x) + if s.columns > 1 { + // Windows 10 needs a spare column for the cursor + s.columns-- + } +} diff --git a/vendor/github.com/peterh/liner/signal.go b/vendor/github.com/peterh/liner/signal.go new file mode 100644 index 0000000..0cba79e --- /dev/null +++ b/vendor/github.com/peterh/liner/signal.go @@ -0,0 +1,12 @@ +// +build go1.1,!windows + +package liner + +import ( + "os" + "os/signal" +) + +func stopSignal(c chan<- os.Signal) { + signal.Stop(c) +} diff --git a/vendor/github.com/peterh/liner/signal_legacy.go b/vendor/github.com/peterh/liner/signal_legacy.go new file mode 100644 index 0000000..fa3672d --- /dev/null +++ b/vendor/github.com/peterh/liner/signal_legacy.go @@ -0,0 +1,11 @@ +// +build !go1.1,!windows + +package liner + +import ( + "os" +) + +func stopSignal(c chan<- os.Signal) { + // signal.Stop does not exist before Go 1.1 +} diff --git a/vendor/github.com/peterh/liner/unixmode.go b/vendor/github.com/peterh/liner/unixmode.go new file mode 100644 index 0000000..9838923 --- /dev/null +++ b/vendor/github.com/peterh/liner/unixmode.go @@ -0,0 +1,37 @@ +// +build linux darwin freebsd openbsd netbsd + +package liner + +import ( + "syscall" + "unsafe" +) + +func (mode *termios) ApplyMode() error { + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode))) + + if errno != 0 { + return errno + } + return nil +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + mode, errno := getMode(syscall.Stdin) + + if errno != 0 { + return nil, errno + } + return mode, nil +} + +func getMode(handle int) (*termios, syscall.Errno) { + var mode termios + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode))) + + return &mode, errno +} diff --git a/vendor/github.com/peterh/liner/width.go b/vendor/github.com/peterh/liner/width.go new file mode 100644 index 0000000..d8984aa --- /dev/null +++ b/vendor/github.com/peterh/liner/width.go @@ -0,0 +1,79 @@ +package liner + +import "unicode" + +// These character classes are mostly zero width (when combined). +// A few might not be, depending on the user's font. Fixing this +// is non-trivial, given that some terminals don't support +// ANSI DSR/CPR +var zeroWidth = []*unicode.RangeTable{ + unicode.Mn, + unicode.Me, + unicode.Cc, + unicode.Cf, +} + +var doubleWidth = []*unicode.RangeTable{ + unicode.Han, + unicode.Hangul, + unicode.Hiragana, + unicode.Katakana, +} + +// countGlyphs considers zero-width characters to be zero glyphs wide, +// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide. +func countGlyphs(s []rune) int { + n := 0 + for _, r := range s { + switch { + case unicode.IsOneOf(zeroWidth, r): + case unicode.IsOneOf(doubleWidth, r): + n += 2 + default: + n++ + } + } + return n +} + +func countMultiLineGlyphs(s []rune, columns int, start int) int { + n := start + for _, r := range s { + switch { + case unicode.IsOneOf(zeroWidth, r): + case unicode.IsOneOf(doubleWidth, r): + n += 2 + // no room for a 2-glyphs-wide char in the ending + // so skip a column and display it at the beginning + if n%columns == 1 { + n++ + } + default: + n++ + } + } + return n +} + +func getPrefixGlyphs(s []rune, num int) []rune { + p := 0 + for n := 0; n < num && p < len(s); p++ { + if !unicode.IsOneOf(zeroWidth, s[p]) { + n++ + } + } + for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) { + p++ + } + return s[:p] +} + +func getSuffixGlyphs(s []rune, num int) []rune { + p := len(s) + for n := 0; n < num && p > 0; p-- { + if !unicode.IsOneOf(zeroWidth, s[p-1]) { + n++ + } + } + return s[p:] +} diff --git a/vendor/github.com/smartystreets/assertions/LICENSE.md b/vendor/github.com/smartystreets/assertions/LICENSE.md deleted file mode 100644 index 48a3731..0000000 --- a/vendor/github.com/smartystreets/assertions/LICENSE.md +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2015 SmartyStreets, LLC - -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. - -NOTE: Various optional and subordinate components carry their own licensing -requirements and restrictions. Use of those components is subject to the terms -and conditions outlined the respective license of each component. diff --git a/vendor/github.com/smartystreets/assertions/README.md b/vendor/github.com/smartystreets/assertions/README.md deleted file mode 100644 index 19a6632..0000000 --- a/vendor/github.com/smartystreets/assertions/README.md +++ /dev/null @@ -1,554 +0,0 @@ -# assertions --- - import "github.com/smartystreets/assertions" - -Package assertions contains the implementations for all assertions which are -referenced in goconvey's `convey` package -(github.com/smartystreets/goconvey/convey) for use with the So(...) method. They -can also be used in traditional Go test functions and even in applicaitons. - -## Usage - -#### func GoConveyMode - -```go -func GoConveyMode(yes bool) -``` -GoConveyMode provides control over JSON serialization of failures. When using -the assertions in this package from the convey package JSON results are very -helpful and can be rendered in a DIFF view. In that case, this function will be -called with a true value to enable the JSON serialization. By default, the -assertions in this package will not serializer a JSON result, making standalone -ussage more convenient. - -#### func ShouldAlmostEqual - -```go -func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string -``` -ShouldAlmostEqual makes sure that two parameters are close enough to being -equal. The acceptable delta may be specified with a third argument, or a very -small default delta will be used. - -#### func ShouldBeBetween - -```go -func ShouldBeBetween(actual interface{}, expected ...interface{}) string -``` -ShouldBeBetween receives exactly three parameters: an actual value, a lower -bound, and an upper bound. It ensures that the actual value is between both -bounds (but not equal to either of them). - -#### func ShouldBeBetweenOrEqual - -```go -func ShouldBeBetweenOrEqual(actual interface{}, expected ...interface{}) string -``` -ShouldBeBetweenOrEqual receives exactly three parameters: an actual value, a -lower bound, and an upper bound. It ensures that the actual value is between -both bounds or equal to one of them. - -#### func ShouldBeBlank - -```go -func ShouldBeBlank(actual interface{}, expected ...interface{}) string -``` -ShouldBeBlank receives exactly 1 string parameter and ensures that it is equal -to "". - -#### func ShouldBeChronological - -```go -func ShouldBeChronological(actual interface{}, expected ...interface{}) string -``` -ShouldBeChronological receives a []time.Time slice and asserts that the are in -chronological order starting with the first time.Time as the earliest. - -#### func ShouldBeEmpty - -```go -func ShouldBeEmpty(actual interface{}, expected ...interface{}) string -``` -ShouldBeEmpty receives a single parameter (actual) and determines whether or not -calling len(actual) would return `0`. It obeys the rules specified by the len -function for determining length: http://golang.org/pkg/builtin/#len - -#### func ShouldBeFalse - -```go -func ShouldBeFalse(actual interface{}, expected ...interface{}) string -``` -ShouldBeFalse receives a single parameter and ensures that it is false. - -#### func ShouldBeGreaterThan - -```go -func ShouldBeGreaterThan(actual interface{}, expected ...interface{}) string -``` -ShouldBeGreaterThan receives exactly two parameters and ensures that the first -is greater than the second. - -#### func ShouldBeGreaterThanOrEqualTo - -```go -func ShouldBeGreaterThanOrEqualTo(actual interface{}, expected ...interface{}) string -``` -ShouldBeGreaterThanOrEqualTo receives exactly two parameters and ensures that -the first is greater than or equal to the second. - -#### func ShouldBeIn - -```go -func ShouldBeIn(actual interface{}, expected ...interface{}) string -``` -ShouldBeIn receives at least 2 parameters. The first is a proposed member of the -collection that is passed in either as the second parameter, or of the -collection that is comprised of all the remaining parameters. This assertion -ensures that the proposed member is in the collection (using ShouldEqual). - -#### func ShouldBeLessThan - -```go -func ShouldBeLessThan(actual interface{}, expected ...interface{}) string -``` -ShouldBeLessThan receives exactly two parameters and ensures that the first is -less than the second. - -#### func ShouldBeLessThanOrEqualTo - -```go -func ShouldBeLessThanOrEqualTo(actual interface{}, expected ...interface{}) string -``` -ShouldBeLessThan receives exactly two parameters and ensures that the first is -less than or equal to the second. - -#### func ShouldBeNil - -```go -func ShouldBeNil(actual interface{}, expected ...interface{}) string -``` -ShouldBeNil receives a single parameter and ensures that it is nil. - -#### func ShouldBeTrue - -```go -func ShouldBeTrue(actual interface{}, expected ...interface{}) string -``` -ShouldBeTrue receives a single parameter and ensures that it is true. - -#### func ShouldBeZeroValue - -```go -func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string -``` -ShouldBeZeroValue receives a single parameter and ensures that it is the Go -equivalent of the default value, or "zero" value. - -#### func ShouldContain - -```go -func ShouldContain(actual interface{}, expected ...interface{}) string -``` -ShouldContain receives exactly two parameters. The first is a slice and the -second is a proposed member. Membership is determined using ShouldEqual. - -#### func ShouldContainKey - -```go -func ShouldContainKey(actual interface{}, expected ...interface{}) string -``` -ShouldContainKey receives exactly two parameters. The first is a map and the -second is a proposed key. Keys are compared with a simple '=='. - -#### func ShouldContainSubstring - -```go -func ShouldContainSubstring(actual interface{}, expected ...interface{}) string -``` -ShouldContainSubstring receives exactly 2 string parameters and ensures that the -first contains the second as a substring. - -#### func ShouldEndWith - -```go -func ShouldEndWith(actual interface{}, expected ...interface{}) string -``` -ShouldEndWith receives exactly 2 string parameters and ensures that the first -ends with the second. - -#### func ShouldEqual - -```go -func ShouldEqual(actual interface{}, expected ...interface{}) string -``` -ShouldEqual receives exactly two parameters and does an equality check. - -#### func ShouldEqualTrimSpace - -```go -func ShouldEqualTrimSpace(actual interface{}, expected ...interface{}) string -``` -ShouldEqualTrimSpace receives exactly 2 string parameters and ensures that the -first is equal to the second after removing all leading and trailing whitespace -using strings.TrimSpace(first). - -#### func ShouldEqualWithout - -```go -func ShouldEqualWithout(actual interface{}, expected ...interface{}) string -``` -ShouldEqualWithout receives exactly 3 string parameters and ensures that the -first is equal to the second after removing all instances of the third from the -first using strings.Replace(first, third, "", -1). - -#### func ShouldHappenAfter - -```go -func ShouldHappenAfter(actual interface{}, expected ...interface{}) string -``` -ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the -first happens after the second. - -#### func ShouldHappenBefore - -```go -func ShouldHappenBefore(actual interface{}, expected ...interface{}) string -``` -ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the -first happens before the second. - -#### func ShouldHappenBetween - -```go -func ShouldHappenBetween(actual interface{}, expected ...interface{}) string -``` -ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the -first happens between (not on) the second and third. - -#### func ShouldHappenOnOrAfter - -```go -func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string -``` -ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that -the first happens on or after the second. - -#### func ShouldHappenOnOrBefore - -```go -func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string -``` -ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that -the first happens on or before the second. - -#### func ShouldHappenOnOrBetween - -```go -func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string -``` -ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that -the first happens between or on the second and third. - -#### func ShouldHappenWithin - -```go -func ShouldHappenWithin(actual interface{}, expected ...interface{}) string -``` -ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 -arguments) and asserts that the first time.Time happens within or on the -duration specified relative to the other time.Time. - -#### func ShouldHaveLength - -```go -func ShouldHaveLength(actual interface{}, expected ...interface{}) string -``` -ShouldHaveLength receives a collection and a positive integer and asserts that -the length of the collection is equal to the integer provided. - -#### func ShouldHaveSameTypeAs - -```go -func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string -``` -ShouldHaveSameTypeAs receives exactly two parameters and compares their -underlying types for equality. - -#### func ShouldImplement - -```go -func ShouldImplement(actual interface{}, expectedList ...interface{}) string -``` -ShouldImplement receives exactly two parameters and ensures that the first -implements the interface type of the second. - -#### func ShouldNotAlmostEqual - -```go -func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string -``` -ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual - -#### func ShouldNotBeBetween - -```go -func ShouldNotBeBetween(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeBetween receives exactly three parameters: an actual value, a lower -bound, and an upper bound. It ensures that the actual value is NOT between both -bounds. - -#### func ShouldNotBeBetweenOrEqual - -```go -func ShouldNotBeBetweenOrEqual(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeBetweenOrEqual receives exactly three parameters: an actual value, a -lower bound, and an upper bound. It ensures that the actual value is nopt -between the bounds nor equal to either of them. - -#### func ShouldNotBeBlank - -```go -func ShouldNotBeBlank(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeBlank receives exactly 1 string parameter and ensures that it is -equal to "". - -#### func ShouldNotBeEmpty - -```go -func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeEmpty receives a single parameter (actual) and determines whether or -not calling len(actual) would return a value greater than zero. It obeys the -rules specified by the `len` function for determining length: -http://golang.org/pkg/builtin/#len - -#### func ShouldNotBeIn - -```go -func ShouldNotBeIn(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of -the collection that is passed in either as the second parameter, or of the -collection that is comprised of all the remaining parameters. This assertion -ensures that the proposed member is NOT in the collection (using ShouldEqual). - -#### func ShouldNotBeNil - -```go -func ShouldNotBeNil(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeNil receives a single parameter and ensures that it is not nil. - -#### func ShouldNotContain - -```go -func ShouldNotContain(actual interface{}, expected ...interface{}) string -``` -ShouldNotContain receives exactly two parameters. The first is a slice and the -second is a proposed member. Membership is determinied using ShouldEqual. - -#### func ShouldNotContainKey - -```go -func ShouldNotContainKey(actual interface{}, expected ...interface{}) string -``` -ShouldNotContainKey receives exactly two parameters. The first is a map and the -second is a proposed absent key. Keys are compared with a simple '=='. - -#### func ShouldNotContainSubstring - -```go -func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string -``` -ShouldNotContainSubstring receives exactly 2 string parameters and ensures that -the first does NOT contain the second as a substring. - -#### func ShouldNotEndWith - -```go -func ShouldNotEndWith(actual interface{}, expected ...interface{}) string -``` -ShouldEndWith receives exactly 2 string parameters and ensures that the first -does not end with the second. - -#### func ShouldNotEqual - -```go -func ShouldNotEqual(actual interface{}, expected ...interface{}) string -``` -ShouldNotEqual receives exactly two parameters and does an inequality check. - -#### func ShouldNotHappenOnOrBetween - -```go -func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string -``` -ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts -that the first does NOT happen between or on the second or third. - -#### func ShouldNotHappenWithin - -```go -func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string -``` -ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 -arguments) and asserts that the first time.Time does NOT happen within or on the -duration specified relative to the other time.Time. - -#### func ShouldNotHaveSameTypeAs - -```go -func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string -``` -ShouldNotHaveSameTypeAs receives exactly two parameters and compares their -underlying types for inequality. - -#### func ShouldNotImplement - -```go -func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string -``` -ShouldNotImplement receives exactly two parameters and ensures that the first -does NOT implement the interface type of the second. - -#### func ShouldNotPanic - -```go -func ShouldNotPanic(actual interface{}, expected ...interface{}) (message string) -``` -ShouldNotPanic receives a void, niladic function and expects to execute the -function without any panic. - -#### func ShouldNotPanicWith - -```go -func ShouldNotPanicWith(actual interface{}, expected ...interface{}) (message string) -``` -ShouldNotPanicWith receives a void, niladic function and expects to recover a -panic whose content differs from the second argument. - -#### func ShouldNotPointTo - -```go -func ShouldNotPointTo(actual interface{}, expected ...interface{}) string -``` -ShouldNotPointTo receives exactly two parameters and checks to see that they -point to different addresess. - -#### func ShouldNotResemble - -```go -func ShouldNotResemble(actual interface{}, expected ...interface{}) string -``` -ShouldNotResemble receives exactly two parameters and does an inverse deep equal -check (see reflect.DeepEqual) - -#### func ShouldNotStartWith - -```go -func ShouldNotStartWith(actual interface{}, expected ...interface{}) string -``` -ShouldNotStartWith receives exactly 2 string parameters and ensures that the -first does not start with the second. - -#### func ShouldPanic - -```go -func ShouldPanic(actual interface{}, expected ...interface{}) (message string) -``` -ShouldPanic receives a void, niladic function and expects to recover a panic. - -#### func ShouldPanicWith - -```go -func ShouldPanicWith(actual interface{}, expected ...interface{}) (message string) -``` -ShouldPanicWith receives a void, niladic function and expects to recover a panic -with the second argument as the content. - -#### func ShouldPointTo - -```go -func ShouldPointTo(actual interface{}, expected ...interface{}) string -``` -ShouldPointTo receives exactly two parameters and checks to see that they point -to the same address. - -#### func ShouldResemble - -```go -func ShouldResemble(actual interface{}, expected ...interface{}) string -``` -ShouldResemble receives exactly two parameters and does a deep equal check (see -reflect.DeepEqual) - -#### func ShouldStartWith - -```go -func ShouldStartWith(actual interface{}, expected ...interface{}) string -``` -ShouldStartWith receives exactly 2 string parameters and ensures that the first -starts with the second. - -#### func So - -```go -func So(actual interface{}, assert assertion, expected ...interface{}) (bool, string) -``` -So is a convenience function (as opposed to an inconvenience function?) for -running assertions on arbitrary arguments in any context, be it for testing or -even application logging. It allows you to perform assertion-like behavior (and -get nicely formatted messages detailing discrepancies) but without the program -blowing up or panicking. All that is required is to import this package and call -`So` with one of the assertions exported by this package as the second -parameter. The first return parameter is a boolean indicating if the assertion -was true. The second return parameter is the well-formatted message showing why -an assertion was incorrect, or blank if the assertion was correct. - -Example: - - if ok, message := So(x, ShouldBeGreaterThan, y); !ok { - log.Println(message) - } - -#### type Assertion - -```go -type Assertion struct { -} -``` - - -#### func New - -```go -func New(t testingT) *Assertion -``` -New swallows the *testing.T struct and prints failed assertions using t.Error. -Example: assertions.New(t).So(1, should.Equal, 1) - -#### func (*Assertion) Failed - -```go -func (this *Assertion) Failed() bool -``` -Failed reports whether any calls to So (on this Assertion instance) have failed. - -#### func (*Assertion) So - -```go -func (this *Assertion) So(actual interface{}, assert assertion, expected ...interface{}) bool -``` -So calls the standalone So function and additionally, calls t.Error in failure -scenarios. - -#### type Serializer - -```go -type Serializer interface { - // contains filtered or unexported methods -} -``` diff --git a/vendor/github.com/smartystreets/assertions/assertions.goconvey b/vendor/github.com/smartystreets/assertions/assertions.goconvey deleted file mode 100644 index e76cf27..0000000 --- a/vendor/github.com/smartystreets/assertions/assertions.goconvey +++ /dev/null @@ -1,3 +0,0 @@ -#ignore --timeout=1s --coverpkg=github.com/smartystreets/assertions,github.com/smartystreets/assertions/internal/oglematchers \ No newline at end of file diff --git a/vendor/github.com/smartystreets/assertions/collections.go b/vendor/github.com/smartystreets/assertions/collections.go deleted file mode 100644 index de0f442..0000000 --- a/vendor/github.com/smartystreets/assertions/collections.go +++ /dev/null @@ -1,250 +0,0 @@ -package assertions - -import ( - "fmt" - "reflect" - - "github.com/smartystreets/assertions/internal/oglematchers" -) - -// ShouldContain receives exactly two parameters. The first is a slice and the -// second is a proposed member. Membership is determined using ShouldEqual. -func ShouldContain(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil { - typeName := reflect.TypeOf(actual) - - if fmt.Sprintf("%v", matchError) == "which is not a slice or array" { - return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName) - } - return fmt.Sprintf(shouldHaveContained, typeName, expected[0]) - } - return success -} - -// ShouldNotContain receives exactly two parameters. The first is a slice and the -// second is a proposed member. Membership is determinied using ShouldEqual. -func ShouldNotContain(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - typeName := reflect.TypeOf(actual) - - if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil { - if fmt.Sprintf("%v", matchError) == "which is not a slice or array" { - return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName) - } - return success - } - return fmt.Sprintf(shouldNotHaveContained, typeName, expected[0]) -} - -// ShouldContainKey receives exactly two parameters. The first is a map and the -// second is a proposed key. Keys are compared with a simple '=='. -func ShouldContainKey(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - keys, isMap := mapKeys(actual) - if !isMap { - return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual)) - } - - if !keyFound(keys, expected[0]) { - return fmt.Sprintf(shouldHaveContainedKey, reflect.TypeOf(actual), expected) - } - - return "" -} - -// ShouldNotContainKey receives exactly two parameters. The first is a map and the -// second is a proposed absent key. Keys are compared with a simple '=='. -func ShouldNotContainKey(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - keys, isMap := mapKeys(actual) - if !isMap { - return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual)) - } - - if keyFound(keys, expected[0]) { - return fmt.Sprintf(shouldNotHaveContainedKey, reflect.TypeOf(actual), expected) - } - - return "" -} - -func mapKeys(m interface{}) ([]reflect.Value, bool) { - value := reflect.ValueOf(m) - if value.Kind() != reflect.Map { - return nil, false - } - return value.MapKeys(), true -} -func keyFound(keys []reflect.Value, expectedKey interface{}) bool { - found := false - for _, key := range keys { - if key.Interface() == expectedKey { - found = true - } - } - return found -} - -// ShouldBeIn receives at least 2 parameters. The first is a proposed member of the collection -// that is passed in either as the second parameter, or of the collection that is comprised -// of all the remaining parameters. This assertion ensures that the proposed member is in -// the collection (using ShouldEqual). -func ShouldBeIn(actual interface{}, expected ...interface{}) string { - if fail := atLeast(1, expected); fail != success { - return fail - } - - if len(expected) == 1 { - return shouldBeIn(actual, expected[0]) - } - return shouldBeIn(actual, expected) -} -func shouldBeIn(actual interface{}, expected interface{}) string { - if matchError := oglematchers.Contains(actual).Matches(expected); matchError != nil { - return fmt.Sprintf(shouldHaveBeenIn, actual, reflect.TypeOf(expected)) - } - return success -} - -// ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of the collection -// that is passed in either as the second parameter, or of the collection that is comprised -// of all the remaining parameters. This assertion ensures that the proposed member is NOT in -// the collection (using ShouldEqual). -func ShouldNotBeIn(actual interface{}, expected ...interface{}) string { - if fail := atLeast(1, expected); fail != success { - return fail - } - - if len(expected) == 1 { - return shouldNotBeIn(actual, expected[0]) - } - return shouldNotBeIn(actual, expected) -} -func shouldNotBeIn(actual interface{}, expected interface{}) string { - if matchError := oglematchers.Contains(actual).Matches(expected); matchError == nil { - return fmt.Sprintf(shouldNotHaveBeenIn, actual, reflect.TypeOf(expected)) - } - return success -} - -// ShouldBeEmpty receives a single parameter (actual) and determines whether or not -// calling len(actual) would return `0`. It obeys the rules specified by the len -// function for determining length: http://golang.org/pkg/builtin/#len -func ShouldBeEmpty(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } - - if actual == nil { - return success - } - - value := reflect.ValueOf(actual) - switch value.Kind() { - case reflect.Slice: - if value.Len() == 0 { - return success - } - case reflect.Chan: - if value.Len() == 0 { - return success - } - case reflect.Map: - if value.Len() == 0 { - return success - } - case reflect.String: - if value.Len() == 0 { - return success - } - case reflect.Ptr: - elem := value.Elem() - kind := elem.Kind() - if (kind == reflect.Slice || kind == reflect.Array) && elem.Len() == 0 { - return success - } - } - - return fmt.Sprintf(shouldHaveBeenEmpty, actual) -} - -// ShouldNotBeEmpty receives a single parameter (actual) and determines whether or not -// calling len(actual) would return a value greater than zero. It obeys the rules -// specified by the `len` function for determining length: http://golang.org/pkg/builtin/#len -func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } - - if empty := ShouldBeEmpty(actual, expected...); empty != success { - return success - } - return fmt.Sprintf(shouldNotHaveBeenEmpty, actual) -} - -// ShouldHaveLength receives 2 parameters. The first is a collection to check -// the length of, the second being the expected length. It obeys the rules -// specified by the len function for determining length: -// http://golang.org/pkg/builtin/#len -func ShouldHaveLength(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - var expectedLen int64 - lenValue := reflect.ValueOf(expected[0]) - switch lenValue.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - expectedLen = lenValue.Int() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - expectedLen = int64(lenValue.Uint()) - default: - return fmt.Sprintf(shouldHaveBeenAValidInteger, reflect.TypeOf(expected[0])) - } - - if expectedLen < 0 { - return fmt.Sprintf(shouldHaveBeenAValidLength, expected[0]) - } - - value := reflect.ValueOf(actual) - switch value.Kind() { - case reflect.Slice: - if int64(value.Len()) == expectedLen { - return success - } - case reflect.Chan: - if int64(value.Len()) == expectedLen { - return success - } - case reflect.Map: - if int64(value.Len()) == expectedLen { - return success - } - case reflect.String: - if int64(value.Len()) == expectedLen { - return success - } - case reflect.Ptr: - elem := value.Elem() - kind := elem.Kind() - if (kind == reflect.Slice || kind == reflect.Array) && int64(elem.Len()) == expectedLen { - return success - } - default: - return fmt.Sprintf(shouldHaveBeenAValidCollection, reflect.TypeOf(actual)) - } - - return fmt.Sprintf(shouldHaveHadLength, actual, expectedLen) -} diff --git a/vendor/github.com/smartystreets/assertions/doc.go b/vendor/github.com/smartystreets/assertions/doc.go deleted file mode 100644 index d3d116c..0000000 --- a/vendor/github.com/smartystreets/assertions/doc.go +++ /dev/null @@ -1,99 +0,0 @@ -// Package assertions contains the implementations for all assertions which -// are referenced in goconvey's `convey` package -// (github.com/smartystreets/goconvey/convey) for use with the So(...) method. -// They can also be used in traditional Go test functions and even in -// applicaitons. -package assertions - -import ( - "fmt" - "runtime" -) - -// By default we use a no-op serializer. The actual Serializer provides a JSON -// representation of failure results on selected assertions so the goconvey -// web UI can display a convenient diff. -var serializer Serializer = new(noopSerializer) - -// GoConveyMode provides control over JSON serialization of failures. When -// using the assertions in this package from the convey package JSON results -// are very helpful and can be rendered in a DIFF view. In that case, this function -// will be called with a true value to enable the JSON serialization. By default, -// the assertions in this package will not serializer a JSON result, making -// standalone ussage more convenient. -func GoConveyMode(yes bool) { - if yes { - serializer = newSerializer() - } else { - serializer = new(noopSerializer) - } -} - -type testingT interface { - Error(args ...interface{}) -} - -type Assertion struct { - t testingT - failed bool -} - -// New swallows the *testing.T struct and prints failed assertions using t.Error. -// Example: assertions.New(t).So(1, should.Equal, 1) -func New(t testingT) *Assertion { - return &Assertion{t: t} -} - -// Failed reports whether any calls to So (on this Assertion instance) have failed. -func (this *Assertion) Failed() bool { - return this.failed -} - -// So calls the standalone So function and additionally, calls t.Error in failure scenarios. -func (this *Assertion) So(actual interface{}, assert assertion, expected ...interface{}) bool { - ok, result := So(actual, assert, expected...) - if !ok { - this.failed = true - _, file, line, _ := runtime.Caller(1) - this.t.Error(fmt.Sprintf("\n%s:%d\n%s", file, line, result)) - } - return ok -} - -// So is a convenience function (as opposed to an inconvenience function?) -// for running assertions on arbitrary arguments in any context, be it for testing or even -// application logging. It allows you to perform assertion-like behavior (and get nicely -// formatted messages detailing discrepancies) but without the program blowing up or panicking. -// All that is required is to import this package and call `So` with one of the assertions -// exported by this package as the second parameter. -// The first return parameter is a boolean indicating if the assertion was true. The second -// return parameter is the well-formatted message showing why an assertion was incorrect, or -// blank if the assertion was correct. -// -// Example: -// -// if ok, message := So(x, ShouldBeGreaterThan, y); !ok { -// log.Println(message) -// } -// -func So(actual interface{}, assert assertion, expected ...interface{}) (bool, string) { - if result := so(actual, assert, expected...); len(result) == 0 { - return true, result - } else { - return false, result - } -} - -// so is like So, except that it only returns the string message, which is blank if the -// assertion passed. Used to facilitate testing. -func so(actual interface{}, assert func(interface{}, ...interface{}) string, expected ...interface{}) string { - return assert(actual, expected...) -} - -// assertion is an alias for a function with a signature that the So() -// function can handle. Any future or custom assertions should conform to this -// method signature. The return value should be an empty string if the assertion -// passes and a well-formed failure message if not. -type assertion func(actual interface{}, expected ...interface{}) string - -//////////////////////////////////////////////////////////////////////////// diff --git a/vendor/github.com/smartystreets/assertions/equality.go b/vendor/github.com/smartystreets/assertions/equality.go deleted file mode 100644 index 95cd347..0000000 --- a/vendor/github.com/smartystreets/assertions/equality.go +++ /dev/null @@ -1,286 +0,0 @@ -package assertions - -import ( - "errors" - "fmt" - "math" - "reflect" - "strings" - - "github.com/smartystreets/assertions/internal/oglematchers" -) - -// default acceptable delta for ShouldAlmostEqual -const defaultDelta = 0.0000000001 - -// ShouldEqual receives exactly two parameters and does an equality check. -func ShouldEqual(actual interface{}, expected ...interface{}) string { - if message := need(1, expected); message != success { - return message - } - return shouldEqual(actual, expected[0]) -} -func shouldEqual(actual, expected interface{}) (message string) { - defer func() { - if r := recover(); r != nil { - message = serializer.serialize(expected, actual, fmt.Sprintf(shouldHaveBeenEqual, expected, actual)) - return - } - }() - - if matchError := oglematchers.Equals(expected).Matches(actual); matchError != nil { - expectedSyntax := fmt.Sprintf("%v", expected) - actualSyntax := fmt.Sprintf("%v", actual) - if expectedSyntax == actualSyntax && reflect.TypeOf(expected) != reflect.TypeOf(actual) { - message = fmt.Sprintf(shouldHaveBeenEqualTypeMismatch, expected, expected, actual, actual) - } else { - message = fmt.Sprintf(shouldHaveBeenEqual, expected, actual) - } - message = serializer.serialize(expected, actual, message) - return - } - - return success -} - -// ShouldNotEqual receives exactly two parameters and does an inequality check. -func ShouldNotEqual(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } else if ShouldEqual(actual, expected[0]) == success { - return fmt.Sprintf(shouldNotHaveBeenEqual, actual, expected[0]) - } - return success -} - -// ShouldAlmostEqual makes sure that two parameters are close enough to being equal. -// The acceptable delta may be specified with a third argument, -// or a very small default delta will be used. -func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string { - actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...) - - if err != "" { - return err - } - - if math.Abs(actualFloat-expectedFloat) <= deltaFloat { - return success - } else { - return fmt.Sprintf(shouldHaveBeenAlmostEqual, actualFloat, expectedFloat) - } -} - -// ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual -func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string { - actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...) - - if err != "" { - return err - } - - if math.Abs(actualFloat-expectedFloat) > deltaFloat { - return success - } else { - return fmt.Sprintf(shouldHaveNotBeenAlmostEqual, actualFloat, expectedFloat) - } -} - -func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64, float64, float64, string) { - deltaFloat := 0.0000000001 - - if len(expected) == 0 { - return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided neither)" - } else if len(expected) == 2 { - delta, err := getFloat(expected[1]) - - if err != nil { - return 0.0, 0.0, 0.0, "delta must be a numerical type" - } - - deltaFloat = delta - } else if len(expected) > 2 { - return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided more values)" - } - - actualFloat, err := getFloat(actual) - - if err != nil { - return 0.0, 0.0, 0.0, err.Error() - } - - expectedFloat, err := getFloat(expected[0]) - - if err != nil { - return 0.0, 0.0, 0.0, err.Error() - } - - return actualFloat, expectedFloat, deltaFloat, "" -} - -// returns the float value of any real number, or error if it is not a numerical type -func getFloat(num interface{}) (float64, error) { - numValue := reflect.ValueOf(num) - numKind := numValue.Kind() - - if numKind == reflect.Int || - numKind == reflect.Int8 || - numKind == reflect.Int16 || - numKind == reflect.Int32 || - numKind == reflect.Int64 { - return float64(numValue.Int()), nil - } else if numKind == reflect.Uint || - numKind == reflect.Uint8 || - numKind == reflect.Uint16 || - numKind == reflect.Uint32 || - numKind == reflect.Uint64 { - return float64(numValue.Uint()), nil - } else if numKind == reflect.Float32 || - numKind == reflect.Float64 { - return numValue.Float(), nil - } else { - return 0.0, errors.New("must be a numerical type, but was " + numKind.String()) - } -} - -// ShouldResemble receives exactly two parameters and does a deep equal check (see reflect.DeepEqual) -func ShouldResemble(actual interface{}, expected ...interface{}) string { - if message := need(1, expected); message != success { - return message - } - - if matchError := oglematchers.DeepEquals(expected[0]).Matches(actual); matchError != nil { - expectedSyntax := fmt.Sprintf("%#v", expected[0]) - actualSyntax := fmt.Sprintf("%#v", actual) - var message string - if expectedSyntax == actualSyntax { - message = fmt.Sprintf(shouldHaveResembledTypeMismatch, expected[0], expected[0], actual, actual) - } else { - message = fmt.Sprintf(shouldHaveResembled, expected[0], actual) - } - return serializer.serializeDetailed(expected[0], actual, message) - } - - return success -} - -// ShouldNotResemble receives exactly two parameters and does an inverse deep equal check (see reflect.DeepEqual) -func ShouldNotResemble(actual interface{}, expected ...interface{}) string { - if message := need(1, expected); message != success { - return message - } else if ShouldResemble(actual, expected[0]) == success { - return fmt.Sprintf(shouldNotHaveResembled, actual, expected[0]) - } - return success -} - -// ShouldPointTo receives exactly two parameters and checks to see that they point to the same address. -func ShouldPointTo(actual interface{}, expected ...interface{}) string { - if message := need(1, expected); message != success { - return message - } - return shouldPointTo(actual, expected[0]) - -} -func shouldPointTo(actual, expected interface{}) string { - actualValue := reflect.ValueOf(actual) - expectedValue := reflect.ValueOf(expected) - - if ShouldNotBeNil(actual) != success { - return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "nil") - } else if ShouldNotBeNil(expected) != success { - return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "nil") - } else if actualValue.Kind() != reflect.Ptr { - return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "not") - } else if expectedValue.Kind() != reflect.Ptr { - return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "not") - } else if ShouldEqual(actualValue.Pointer(), expectedValue.Pointer()) != success { - actualAddress := reflect.ValueOf(actual).Pointer() - expectedAddress := reflect.ValueOf(expected).Pointer() - return serializer.serialize(expectedAddress, actualAddress, fmt.Sprintf(shouldHavePointedTo, - actual, actualAddress, - expected, expectedAddress)) - } - return success -} - -// ShouldNotPointTo receives exactly two parameters and checks to see that they point to different addresess. -func ShouldNotPointTo(actual interface{}, expected ...interface{}) string { - if message := need(1, expected); message != success { - return message - } - compare := ShouldPointTo(actual, expected[0]) - if strings.HasPrefix(compare, shouldBePointers) { - return compare - } else if compare == success { - return fmt.Sprintf(shouldNotHavePointedTo, actual, expected[0], reflect.ValueOf(actual).Pointer()) - } - return success -} - -// ShouldBeNil receives a single parameter and ensures that it is nil. -func ShouldBeNil(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } else if actual == nil { - return success - } else if interfaceHasNilValue(actual) { - return success - } - return fmt.Sprintf(shouldHaveBeenNil, actual) -} -func interfaceHasNilValue(actual interface{}) bool { - value := reflect.ValueOf(actual) - kind := value.Kind() - nilable := kind == reflect.Slice || - kind == reflect.Chan || - kind == reflect.Func || - kind == reflect.Ptr || - kind == reflect.Map - - // Careful: reflect.Value.IsNil() will panic unless it's an interface, chan, map, func, slice, or ptr - // Reference: http://golang.org/pkg/reflect/#Value.IsNil - return nilable && value.IsNil() -} - -// ShouldNotBeNil receives a single parameter and ensures that it is not nil. -func ShouldNotBeNil(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } else if ShouldBeNil(actual) == success { - return fmt.Sprintf(shouldNotHaveBeenNil, actual) - } - return success -} - -// ShouldBeTrue receives a single parameter and ensures that it is true. -func ShouldBeTrue(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } else if actual != true { - return fmt.Sprintf(shouldHaveBeenTrue, actual) - } - return success -} - -// ShouldBeFalse receives a single parameter and ensures that it is false. -func ShouldBeFalse(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } else if actual != false { - return fmt.Sprintf(shouldHaveBeenFalse, actual) - } - return success -} - -// ShouldBeZeroValue receives a single parameter and ensures that it is -// the Go equivalent of the default value, or "zero" value. -func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } - zeroVal := reflect.Zero(reflect.TypeOf(actual)).Interface() - if !reflect.DeepEqual(zeroVal, actual) { - return serializer.serialize(zeroVal, actual, fmt.Sprintf(shouldHaveBeenZeroValue, actual)) - } - return success -} diff --git a/vendor/github.com/smartystreets/assertions/filter.go b/vendor/github.com/smartystreets/assertions/filter.go deleted file mode 100644 index ee368a9..0000000 --- a/vendor/github.com/smartystreets/assertions/filter.go +++ /dev/null @@ -1,23 +0,0 @@ -package assertions - -import "fmt" - -const ( - success = "" - needExactValues = "This assertion requires exactly %d comparison values (you provided %d)." - needNonEmptyCollection = "This assertion requires at least 1 comparison value (you provided 0)." -) - -func need(needed int, expected []interface{}) string { - if len(expected) != needed { - return fmt.Sprintf(needExactValues, needed, len(expected)) - } - return success -} - -func atLeast(minimum int, expected []interface{}) string { - if len(expected) < 1 { - return needNonEmptyCollection - } - return success -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/LICENSE b/vendor/github.com/smartystreets/assertions/internal/oglematchers/LICENSE deleted file mode 100644 index d645695..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md b/vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md deleted file mode 100644 index 215a2bb..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md +++ /dev/null @@ -1,58 +0,0 @@ -[![GoDoc](https://godoc.org/github.com/smartystreets/assertions/internal/oglematchers?status.svg)](https://godoc.org/github.com/smartystreets/assertions/internal/oglematchers) - -`oglematchers` is a package for the Go programming language containing a set of -matchers, useful in a testing or mocking framework, inspired by and mostly -compatible with [Google Test][googletest] for C++ and -[Google JS Test][google-js-test]. The package is used by the -[ogletest][ogletest] testing framework and [oglemock][oglemock] mocking -framework, which may be more directly useful to you, but can be generically used -elsewhere as well. - -A "matcher" is simply an object with a `Matches` method defining a set of golang -values matched by the matcher, and a `Description` method describing that set. -For example, here are some matchers: - -```go -// Numbers -Equals(17.13) -LessThan(19) - -// Strings -Equals("taco") -HasSubstr("burrito") -MatchesRegex("t.*o") - -// Combining matchers -AnyOf(LessThan(17), GreaterThan(19)) -``` - -There are lots more; see [here][reference] for a reference. You can also add -your own simply by implementing the `oglematchers.Matcher` interface. - - -Installation ------------- - -First, make sure you have installed Go 1.0.2 or newer. See -[here][golang-install] for instructions. - -Use the following command to install `oglematchers` and keep it up to date: - - go get -u github.com/smartystreets/assertions/internal/oglematchers - - -Documentation -------------- - -See [here][reference] for documentation. Alternatively, you can install the -package and then use `godoc`: - - godoc github.com/smartystreets/assertions/internal/oglematchers - - -[reference]: http://godoc.org/github.com/smartystreets/assertions/internal/oglematchers -[golang-install]: http://golang.org/doc/install.html -[googletest]: http://code.google.com/p/googletest/ -[google-js-test]: http://code.google.com/p/google-js-test/ -[ogletest]: http://github.com/smartystreets/assertions/internal/ogletest -[oglemock]: http://github.com/smartystreets/assertions/internal/oglemock diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go deleted file mode 100644 index d93a974..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "strings" -) - -// AllOf accepts a set of matchers S and returns a matcher that follows the -// algorithm below when considering a candidate c: -// -// 1. Return true if for every Matcher m in S, m matches c. -// -// 2. Otherwise, if there is a matcher m in S such that m returns a fatal -// error for c, return that matcher's error message. -// -// 3. Otherwise, return false with the error from some wrapped matcher. -// -// This is akin to a logical AND operation for matchers. -func AllOf(matchers ...Matcher) Matcher { - return &allOfMatcher{matchers} -} - -type allOfMatcher struct { - wrappedMatchers []Matcher -} - -func (m *allOfMatcher) Description() string { - // Special case: the empty set. - if len(m.wrappedMatchers) == 0 { - return "is anything" - } - - // Join the descriptions for the wrapped matchers. - wrappedDescs := make([]string, len(m.wrappedMatchers)) - for i, wrappedMatcher := range m.wrappedMatchers { - wrappedDescs[i] = wrappedMatcher.Description() - } - - return strings.Join(wrappedDescs, ", and ") -} - -func (m *allOfMatcher) Matches(c interface{}) (err error) { - for _, wrappedMatcher := range m.wrappedMatchers { - if wrappedErr := wrappedMatcher.Matches(c); wrappedErr != nil { - err = wrappedErr - - // If the error is fatal, return immediately with this error. - _, ok := wrappedErr.(*FatalError) - if ok { - return - } - } - } - - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go deleted file mode 100644 index f6991ec..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -// Any returns a matcher that matches any value. -func Any() Matcher { - return &anyMatcher{} -} - -type anyMatcher struct { -} - -func (m *anyMatcher) Description() string { - return "is anything" -} - -func (m *anyMatcher) Matches(c interface{}) error { - return nil -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/any_of.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/any_of.go deleted file mode 100644 index 2918b51..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/any_of.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -// AnyOf accepts a set of values S and returns a matcher that follows the -// algorithm below when considering a candidate c: -// -// 1. If there exists a value m in S such that m implements the Matcher -// interface and m matches c, return true. -// -// 2. Otherwise, if there exists a value v in S such that v does not implement -// the Matcher interface and the matcher Equals(v) matches c, return true. -// -// 3. Otherwise, if there is a value m in S such that m implements the Matcher -// interface and m returns a fatal error for c, return that fatal error. -// -// 4. Otherwise, return false. -// -// This is akin to a logical OR operation for matchers, with non-matchers x -// being treated as Equals(x). -func AnyOf(vals ...interface{}) Matcher { - // Get ahold of a type variable for the Matcher interface. - var dummy *Matcher - matcherType := reflect.TypeOf(dummy).Elem() - - // Create a matcher for each value, or use the value itself if it's already a - // matcher. - wrapped := make([]Matcher, len(vals)) - for i, v := range vals { - t := reflect.TypeOf(v) - if t != nil && t.Implements(matcherType) { - wrapped[i] = v.(Matcher) - } else { - wrapped[i] = Equals(v) - } - } - - return &anyOfMatcher{wrapped} -} - -type anyOfMatcher struct { - wrapped []Matcher -} - -func (m *anyOfMatcher) Description() string { - wrappedDescs := make([]string, len(m.wrapped)) - for i, matcher := range m.wrapped { - wrappedDescs[i] = matcher.Description() - } - - return fmt.Sprintf("or(%s)", strings.Join(wrappedDescs, ", ")) -} - -func (m *anyOfMatcher) Matches(c interface{}) (err error) { - err = errors.New("") - - // Try each matcher in turn. - for _, matcher := range m.wrapped { - wrappedErr := matcher.Matches(c) - - // Return immediately if there's a match. - if wrappedErr == nil { - err = nil - return - } - - // Note the fatal error, if any. - if _, isFatal := wrappedErr.(*FatalError); isFatal { - err = wrappedErr - } - } - - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/contains.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/contains.go deleted file mode 100644 index 2f326db..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/contains.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "fmt" - "reflect" -) - -// Return a matcher that matches arrays slices with at least one element that -// matches the supplied argument. If the argument x is not itself a Matcher, -// this is equivalent to Contains(Equals(x)). -func Contains(x interface{}) Matcher { - var result containsMatcher - var ok bool - - if result.elementMatcher, ok = x.(Matcher); !ok { - result.elementMatcher = Equals(x) - } - - return &result -} - -type containsMatcher struct { - elementMatcher Matcher -} - -func (m *containsMatcher) Description() string { - return fmt.Sprintf("contains: %s", m.elementMatcher.Description()) -} - -func (m *containsMatcher) Matches(candidate interface{}) error { - // The candidate must be a slice or an array. - v := reflect.ValueOf(candidate) - if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { - return NewFatalError("which is not a slice or array") - } - - // Check each element. - for i := 0; i < v.Len(); i++ { - elem := v.Index(i) - if matchErr := m.elementMatcher.Matches(elem.Interface()); matchErr == nil { - return nil - } - } - - return fmt.Errorf("") -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/deep_equals.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/deep_equals.go deleted file mode 100644 index 1d91bae..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/deep_equals.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "bytes" - "errors" - "fmt" - "reflect" -) - -var byteSliceType reflect.Type = reflect.TypeOf([]byte{}) - -// DeepEquals returns a matcher that matches based on 'deep equality', as -// defined by the reflect package. This matcher requires that values have -// identical types to x. -func DeepEquals(x interface{}) Matcher { - return &deepEqualsMatcher{x} -} - -type deepEqualsMatcher struct { - x interface{} -} - -func (m *deepEqualsMatcher) Description() string { - xDesc := fmt.Sprintf("%v", m.x) - xValue := reflect.ValueOf(m.x) - - // Special case: fmt.Sprintf presents nil slices as "[]", but - // reflect.DeepEqual makes a distinction between nil and empty slices. Make - // this less confusing. - if xValue.Kind() == reflect.Slice && xValue.IsNil() { - xDesc = "" - } - - return fmt.Sprintf("deep equals: %s", xDesc) -} - -func (m *deepEqualsMatcher) Matches(c interface{}) error { - // Make sure the types match. - ct := reflect.TypeOf(c) - xt := reflect.TypeOf(m.x) - - if ct != xt { - return NewFatalError(fmt.Sprintf("which is of type %v", ct)) - } - - // Special case: handle byte slices more efficiently. - cValue := reflect.ValueOf(c) - xValue := reflect.ValueOf(m.x) - - if ct == byteSliceType && !cValue.IsNil() && !xValue.IsNil() { - xBytes := m.x.([]byte) - cBytes := c.([]byte) - - if bytes.Equal(cBytes, xBytes) { - return nil - } - - return errors.New("") - } - - // Defer to the reflect package. - if reflect.DeepEqual(m.x, c) { - return nil - } - - // Special case: if the comparison failed because c is the nil slice, given - // an indication of this (since its value is printed as "[]"). - if cValue.Kind() == reflect.Slice && cValue.IsNil() { - return errors.New("which is nil") - } - - return errors.New("") -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go deleted file mode 100644 index 2941847..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -// Given a list of arguments M, ElementsAre returns a matcher that matches -// arrays and slices A where all of the following hold: -// -// * A is the same length as M. -// -// * For each i < len(A) where M[i] is a matcher, A[i] matches M[i]. -// -// * For each i < len(A) where M[i] is not a matcher, A[i] matches -// Equals(M[i]). -// -func ElementsAre(M ...interface{}) Matcher { - // Copy over matchers, or convert to Equals(x) for non-matcher x. - subMatchers := make([]Matcher, len(M)) - for i, x := range M { - if matcher, ok := x.(Matcher); ok { - subMatchers[i] = matcher - continue - } - - subMatchers[i] = Equals(x) - } - - return &elementsAreMatcher{subMatchers} -} - -type elementsAreMatcher struct { - subMatchers []Matcher -} - -func (m *elementsAreMatcher) Description() string { - subDescs := make([]string, len(m.subMatchers)) - for i, sm := range m.subMatchers { - subDescs[i] = sm.Description() - } - - return fmt.Sprintf("elements are: [%s]", strings.Join(subDescs, ", ")) -} - -func (m *elementsAreMatcher) Matches(candidates interface{}) error { - // The candidate must be a slice or an array. - v := reflect.ValueOf(candidates) - if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { - return NewFatalError("which is not a slice or array") - } - - // The length must be correct. - if v.Len() != len(m.subMatchers) { - return errors.New(fmt.Sprintf("which is of length %d", v.Len())) - } - - // Check each element. - for i, subMatcher := range m.subMatchers { - c := v.Index(i) - if matchErr := subMatcher.Matches(c.Interface()); matchErr != nil { - // Return an errors indicating which element doesn't match. If the - // matcher error was fatal, make this one fatal too. - err := errors.New(fmt.Sprintf("whose element %d doesn't match", i)) - if _, isFatal := matchErr.(*FatalError); isFatal { - err = NewFatalError(err.Error()) - } - - return err - } - } - - return nil -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/equals.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/equals.go deleted file mode 100644 index a510707..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/equals.go +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "math" - "reflect" -) - -// Equals(x) returns a matcher that matches values v such that v and x are -// equivalent. This includes the case when the comparison v == x using Go's -// built-in comparison operator is legal (except for structs, which this -// matcher does not support), but for convenience the following rules also -// apply: -// -// * Type checking is done based on underlying types rather than actual -// types, so that e.g. two aliases for string can be compared: -// -// type stringAlias1 string -// type stringAlias2 string -// -// a := "taco" -// b := stringAlias1("taco") -// c := stringAlias2("taco") -// -// ExpectTrue(a == b) // Legal, passes -// ExpectTrue(b == c) // Illegal, doesn't compile -// -// ExpectThat(a, Equals(b)) // Passes -// ExpectThat(b, Equals(c)) // Passes -// -// * Values of numeric type are treated as if they were abstract numbers, and -// compared accordingly. Therefore Equals(17) will match int(17), -// int16(17), uint(17), float32(17), complex64(17), and so on. -// -// If you want a stricter matcher that contains no such cleverness, see -// IdenticalTo instead. -// -// Arrays are supported by this matcher, but do not participate in the -// exceptions above. Two arrays compared with this matcher must have identical -// types, and their element type must itself be comparable according to Go's == -// operator. -func Equals(x interface{}) Matcher { - v := reflect.ValueOf(x) - - // This matcher doesn't support structs. - if v.Kind() == reflect.Struct { - panic(fmt.Sprintf("oglematchers.Equals: unsupported kind %v", v.Kind())) - } - - // The == operator is not defined for non-nil slices. - if v.Kind() == reflect.Slice && v.Pointer() != uintptr(0) { - panic(fmt.Sprintf("oglematchers.Equals: non-nil slice")) - } - - return &equalsMatcher{v} -} - -type equalsMatcher struct { - expectedValue reflect.Value -} - -//////////////////////////////////////////////////////////////////////// -// Numeric types -//////////////////////////////////////////////////////////////////////// - -func isSignedInteger(v reflect.Value) bool { - k := v.Kind() - return k >= reflect.Int && k <= reflect.Int64 -} - -func isUnsignedInteger(v reflect.Value) bool { - k := v.Kind() - return k >= reflect.Uint && k <= reflect.Uintptr -} - -func isInteger(v reflect.Value) bool { - return isSignedInteger(v) || isUnsignedInteger(v) -} - -func isFloat(v reflect.Value) bool { - k := v.Kind() - return k == reflect.Float32 || k == reflect.Float64 -} - -func isComplex(v reflect.Value) bool { - k := v.Kind() - return k == reflect.Complex64 || k == reflect.Complex128 -} - -func checkAgainstInt64(e int64, c reflect.Value) (err error) { - err = errors.New("") - - switch { - case isSignedInteger(c): - if c.Int() == e { - err = nil - } - - case isUnsignedInteger(c): - u := c.Uint() - if u <= math.MaxInt64 && int64(u) == e { - err = nil - } - - // Turn around the various floating point types so that the checkAgainst* - // functions for them can deal with precision issues. - case isFloat(c), isComplex(c): - return Equals(c.Interface()).Matches(e) - - default: - err = NewFatalError("which is not numeric") - } - - return -} - -func checkAgainstUint64(e uint64, c reflect.Value) (err error) { - err = errors.New("") - - switch { - case isSignedInteger(c): - i := c.Int() - if i >= 0 && uint64(i) == e { - err = nil - } - - case isUnsignedInteger(c): - if c.Uint() == e { - err = nil - } - - // Turn around the various floating point types so that the checkAgainst* - // functions for them can deal with precision issues. - case isFloat(c), isComplex(c): - return Equals(c.Interface()).Matches(e) - - default: - err = NewFatalError("which is not numeric") - } - - return -} - -func checkAgainstFloat32(e float32, c reflect.Value) (err error) { - err = errors.New("") - - switch { - case isSignedInteger(c): - if float32(c.Int()) == e { - err = nil - } - - case isUnsignedInteger(c): - if float32(c.Uint()) == e { - err = nil - } - - case isFloat(c): - // Compare using float32 to avoid a false sense of precision; otherwise - // e.g. Equals(float32(0.1)) won't match float32(0.1). - if float32(c.Float()) == e { - err = nil - } - - case isComplex(c): - comp := c.Complex() - rl := real(comp) - im := imag(comp) - - // Compare using float32 to avoid a false sense of precision; otherwise - // e.g. Equals(float32(0.1)) won't match (0.1 + 0i). - if im == 0 && float32(rl) == e { - err = nil - } - - default: - err = NewFatalError("which is not numeric") - } - - return -} - -func checkAgainstFloat64(e float64, c reflect.Value) (err error) { - err = errors.New("") - - ck := c.Kind() - - switch { - case isSignedInteger(c): - if float64(c.Int()) == e { - err = nil - } - - case isUnsignedInteger(c): - if float64(c.Uint()) == e { - err = nil - } - - // If the actual value is lower precision, turn the comparison around so we - // apply the low-precision rules. Otherwise, e.g. Equals(0.1) may not match - // float32(0.1). - case ck == reflect.Float32 || ck == reflect.Complex64: - return Equals(c.Interface()).Matches(e) - - // Otherwise, compare with double precision. - case isFloat(c): - if c.Float() == e { - err = nil - } - - case isComplex(c): - comp := c.Complex() - rl := real(comp) - im := imag(comp) - - if im == 0 && rl == e { - err = nil - } - - default: - err = NewFatalError("which is not numeric") - } - - return -} - -func checkAgainstComplex64(e complex64, c reflect.Value) (err error) { - err = errors.New("") - realPart := real(e) - imaginaryPart := imag(e) - - switch { - case isInteger(c) || isFloat(c): - // If we have no imaginary part, then we should just compare against the - // real part. Otherwise, we can't be equal. - if imaginaryPart != 0 { - return - } - - return checkAgainstFloat32(realPart, c) - - case isComplex(c): - // Compare using complex64 to avoid a false sense of precision; otherwise - // e.g. Equals(0.1 + 0i) won't match float32(0.1). - if complex64(c.Complex()) == e { - err = nil - } - - default: - err = NewFatalError("which is not numeric") - } - - return -} - -func checkAgainstComplex128(e complex128, c reflect.Value) (err error) { - err = errors.New("") - realPart := real(e) - imaginaryPart := imag(e) - - switch { - case isInteger(c) || isFloat(c): - // If we have no imaginary part, then we should just compare against the - // real part. Otherwise, we can't be equal. - if imaginaryPart != 0 { - return - } - - return checkAgainstFloat64(realPart, c) - - case isComplex(c): - if c.Complex() == e { - err = nil - } - - default: - err = NewFatalError("which is not numeric") - } - - return -} - -//////////////////////////////////////////////////////////////////////// -// Other types -//////////////////////////////////////////////////////////////////////// - -func checkAgainstBool(e bool, c reflect.Value) (err error) { - if c.Kind() != reflect.Bool { - err = NewFatalError("which is not a bool") - return - } - - err = errors.New("") - if c.Bool() == e { - err = nil - } - return -} - -func checkAgainstChan(e reflect.Value, c reflect.Value) (err error) { - // Create a description of e's type, e.g. "chan int". - typeStr := fmt.Sprintf("%s %s", e.Type().ChanDir(), e.Type().Elem()) - - // Make sure c is a chan of the correct type. - if c.Kind() != reflect.Chan || - c.Type().ChanDir() != e.Type().ChanDir() || - c.Type().Elem() != e.Type().Elem() { - err = NewFatalError(fmt.Sprintf("which is not a %s", typeStr)) - return - } - - err = errors.New("") - if c.Pointer() == e.Pointer() { - err = nil - } - return -} - -func checkAgainstFunc(e reflect.Value, c reflect.Value) (err error) { - // Make sure c is a function. - if c.Kind() != reflect.Func { - err = NewFatalError("which is not a function") - return - } - - err = errors.New("") - if c.Pointer() == e.Pointer() { - err = nil - } - return -} - -func checkAgainstMap(e reflect.Value, c reflect.Value) (err error) { - // Make sure c is a map. - if c.Kind() != reflect.Map { - err = NewFatalError("which is not a map") - return - } - - err = errors.New("") - if c.Pointer() == e.Pointer() { - err = nil - } - return -} - -func checkAgainstPtr(e reflect.Value, c reflect.Value) (err error) { - // Create a description of e's type, e.g. "*int". - typeStr := fmt.Sprintf("*%v", e.Type().Elem()) - - // Make sure c is a pointer of the correct type. - if c.Kind() != reflect.Ptr || - c.Type().Elem() != e.Type().Elem() { - err = NewFatalError(fmt.Sprintf("which is not a %s", typeStr)) - return - } - - err = errors.New("") - if c.Pointer() == e.Pointer() { - err = nil - } - return -} - -func checkAgainstSlice(e reflect.Value, c reflect.Value) (err error) { - // Create a description of e's type, e.g. "[]int". - typeStr := fmt.Sprintf("[]%v", e.Type().Elem()) - - // Make sure c is a slice of the correct type. - if c.Kind() != reflect.Slice || - c.Type().Elem() != e.Type().Elem() { - err = NewFatalError(fmt.Sprintf("which is not a %s", typeStr)) - return - } - - err = errors.New("") - if c.Pointer() == e.Pointer() { - err = nil - } - return -} - -func checkAgainstString(e reflect.Value, c reflect.Value) (err error) { - // Make sure c is a string. - if c.Kind() != reflect.String { - err = NewFatalError("which is not a string") - return - } - - err = errors.New("") - if c.String() == e.String() { - err = nil - } - return -} - -func checkAgainstArray(e reflect.Value, c reflect.Value) (err error) { - // Create a description of e's type, e.g. "[2]int". - typeStr := fmt.Sprintf("%v", e.Type()) - - // Make sure c is the correct type. - if c.Type() != e.Type() { - err = NewFatalError(fmt.Sprintf("which is not %s", typeStr)) - return - } - - // Check for equality. - if e.Interface() != c.Interface() { - err = errors.New("") - return - } - - return -} - -func checkAgainstUnsafePointer(e reflect.Value, c reflect.Value) (err error) { - // Make sure c is a pointer. - if c.Kind() != reflect.UnsafePointer { - err = NewFatalError("which is not a unsafe.Pointer") - return - } - - err = errors.New("") - if c.Pointer() == e.Pointer() { - err = nil - } - return -} - -func checkForNil(c reflect.Value) (err error) { - err = errors.New("") - - // Make sure it is legal to call IsNil. - switch c.Kind() { - case reflect.Invalid: - case reflect.Chan: - case reflect.Func: - case reflect.Interface: - case reflect.Map: - case reflect.Ptr: - case reflect.Slice: - - default: - err = NewFatalError("which cannot be compared to nil") - return - } - - // Ask whether the value is nil. Handle a nil literal (kind Invalid) - // specially, since it's not legal to call IsNil there. - if c.Kind() == reflect.Invalid || c.IsNil() { - err = nil - } - return -} - -//////////////////////////////////////////////////////////////////////// -// Public implementation -//////////////////////////////////////////////////////////////////////// - -func (m *equalsMatcher) Matches(candidate interface{}) error { - e := m.expectedValue - c := reflect.ValueOf(candidate) - ek := e.Kind() - - switch { - case ek == reflect.Bool: - return checkAgainstBool(e.Bool(), c) - - case isSignedInteger(e): - return checkAgainstInt64(e.Int(), c) - - case isUnsignedInteger(e): - return checkAgainstUint64(e.Uint(), c) - - case ek == reflect.Float32: - return checkAgainstFloat32(float32(e.Float()), c) - - case ek == reflect.Float64: - return checkAgainstFloat64(e.Float(), c) - - case ek == reflect.Complex64: - return checkAgainstComplex64(complex64(e.Complex()), c) - - case ek == reflect.Complex128: - return checkAgainstComplex128(complex128(e.Complex()), c) - - case ek == reflect.Chan: - return checkAgainstChan(e, c) - - case ek == reflect.Func: - return checkAgainstFunc(e, c) - - case ek == reflect.Map: - return checkAgainstMap(e, c) - - case ek == reflect.Ptr: - return checkAgainstPtr(e, c) - - case ek == reflect.Slice: - return checkAgainstSlice(e, c) - - case ek == reflect.String: - return checkAgainstString(e, c) - - case ek == reflect.Array: - return checkAgainstArray(e, c) - - case ek == reflect.UnsafePointer: - return checkAgainstUnsafePointer(e, c) - - case ek == reflect.Invalid: - return checkForNil(c) - } - - panic(fmt.Sprintf("equalsMatcher.Matches: unexpected kind: %v", ek)) -} - -func (m *equalsMatcher) Description() string { - // Special case: handle nil. - if !m.expectedValue.IsValid() { - return "is nil" - } - - return fmt.Sprintf("%v", m.expectedValue.Interface()) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go deleted file mode 100644 index 8a078e3..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -// Error returns a matcher that matches non-nil values implementing the -// built-in error interface for whom the return value of Error() matches the -// supplied matcher. -// -// For example: -// -// err := errors.New("taco burrito") -// -// Error(Equals("taco burrito")) // matches err -// Error(HasSubstr("taco")) // matches err -// Error(HasSubstr("enchilada")) // doesn't match err -// -func Error(m Matcher) Matcher { - return &errorMatcher{m} -} - -type errorMatcher struct { - wrappedMatcher Matcher -} - -func (m *errorMatcher) Description() string { - return "error " + m.wrappedMatcher.Description() -} - -func (m *errorMatcher) Matches(c interface{}) error { - // Make sure that c is an error. - e, ok := c.(error) - if !ok { - return NewFatalError("which is not an error") - } - - // Pass on the error text to the wrapped matcher. - return m.wrappedMatcher.Matches(e.Error()) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_or_equal.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_or_equal.go deleted file mode 100644 index 4b9d103..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_or_equal.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "fmt" - "reflect" -) - -// GreaterOrEqual returns a matcher that matches integer, floating point, or -// strings values v such that v >= x. Comparison is not defined between numeric -// and string types, but is defined between all integer and floating point -// types. -// -// x must itself be an integer, floating point, or string type; otherwise, -// GreaterOrEqual will panic. -func GreaterOrEqual(x interface{}) Matcher { - desc := fmt.Sprintf("greater than or equal to %v", x) - - // Special case: make it clear that strings are strings. - if reflect.TypeOf(x).Kind() == reflect.String { - desc = fmt.Sprintf("greater than or equal to \"%s\"", x) - } - - return transformDescription(Not(LessThan(x)), desc) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_than.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_than.go deleted file mode 100644 index 3eef321..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/greater_than.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "fmt" - "reflect" -) - -// GreaterThan returns a matcher that matches integer, floating point, or -// strings values v such that v > x. Comparison is not defined between numeric -// and string types, but is defined between all integer and floating point -// types. -// -// x must itself be an integer, floating point, or string type; otherwise, -// GreaterThan will panic. -func GreaterThan(x interface{}) Matcher { - desc := fmt.Sprintf("greater than %v", x) - - // Special case: make it clear that strings are strings. - if reflect.TypeOf(x).Kind() == reflect.String { - desc = fmt.Sprintf("greater than \"%s\"", x) - } - - return transformDescription(Not(LessOrEqual(x)), desc) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go deleted file mode 100644 index 3b286f7..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "fmt" - "reflect" -) - -// HasSameTypeAs returns a matcher that matches values with exactly the same -// type as the supplied prototype. -func HasSameTypeAs(p interface{}) Matcher { - expected := reflect.TypeOf(p) - pred := func(c interface{}) error { - actual := reflect.TypeOf(c) - if actual != expected { - return fmt.Errorf("which has type %v", actual) - } - - return nil - } - - return NewMatcher(pred, fmt.Sprintf("has type %v", expected)) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go deleted file mode 100644 index bf5bd6a..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -// HasSubstr returns a matcher that matches strings containing s as a -// substring. -func HasSubstr(s string) Matcher { - return NewMatcher( - func(c interface{}) error { return hasSubstr(s, c) }, - fmt.Sprintf("has substring \"%s\"", s)) -} - -func hasSubstr(needle string, c interface{}) error { - v := reflect.ValueOf(c) - if v.Kind() != reflect.String { - return NewFatalError("which is not a string") - } - - // Perform the substring search. - haystack := v.String() - if strings.Contains(haystack, needle) { - return nil - } - - return errors.New("") -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go deleted file mode 100644 index ae6460e..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" -) - -// Is the type comparable according to the definition here? -// -// http://weekly.golang.org/doc/go_spec.html#Comparison_operators -// -func isComparable(t reflect.Type) bool { - switch t.Kind() { - case reflect.Array: - return isComparable(t.Elem()) - - case reflect.Struct: - for i := 0; i < t.NumField(); i++ { - if !isComparable(t.Field(i).Type) { - return false - } - } - - return true - - case reflect.Slice, reflect.Map, reflect.Func: - return false - } - - return true -} - -// Should the supplied type be allowed as an argument to IdenticalTo? -func isLegalForIdenticalTo(t reflect.Type) (bool, error) { - // Allow the zero type. - if t == nil { - return true, nil - } - - // Reference types are always okay; we compare pointers. - switch t.Kind() { - case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: - return true, nil - } - - // Reject other non-comparable types. - if !isComparable(t) { - return false, errors.New(fmt.Sprintf("%v is not comparable", t)) - } - - return true, nil -} - -// IdenticalTo(x) returns a matcher that matches values v with type identical -// to x such that: -// -// 1. If v and x are of a reference type (slice, map, function, channel), then -// they are either both nil or are references to the same object. -// -// 2. Otherwise, if v and x are not of a reference type but have a valid type, -// then v == x. -// -// If v and x are both the invalid type (which results from the predeclared nil -// value, or from nil interface variables), then the matcher is satisfied. -// -// This function will panic if x is of a value type that is not comparable. For -// example, x cannot be an array of functions. -func IdenticalTo(x interface{}) Matcher { - t := reflect.TypeOf(x) - - // Reject illegal arguments. - if ok, err := isLegalForIdenticalTo(t); !ok { - panic("IdenticalTo: " + err.Error()) - } - - return &identicalToMatcher{x} -} - -type identicalToMatcher struct { - x interface{} -} - -func (m *identicalToMatcher) Description() string { - t := reflect.TypeOf(m.x) - return fmt.Sprintf("identical to <%v> %v", t, m.x) -} - -func (m *identicalToMatcher) Matches(c interface{}) error { - // Make sure the candidate's type is correct. - t := reflect.TypeOf(m.x) - if ct := reflect.TypeOf(c); t != ct { - return NewFatalError(fmt.Sprintf("which is of type %v", ct)) - } - - // Special case: two values of the invalid type are always identical. - if t == nil { - return nil - } - - // Handle reference types. - switch t.Kind() { - case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: - xv := reflect.ValueOf(m.x) - cv := reflect.ValueOf(c) - if xv.Pointer() == cv.Pointer() { - return nil - } - - return errors.New("which is not an identical reference") - } - - // Are the values equal? - if m.x == c { - return nil - } - - return errors.New("") -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/less_or_equal.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/less_or_equal.go deleted file mode 100644 index 8402cde..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/less_or_equal.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "fmt" - "reflect" -) - -// LessOrEqual returns a matcher that matches integer, floating point, or -// strings values v such that v <= x. Comparison is not defined between numeric -// and string types, but is defined between all integer and floating point -// types. -// -// x must itself be an integer, floating point, or string type; otherwise, -// LessOrEqual will panic. -func LessOrEqual(x interface{}) Matcher { - desc := fmt.Sprintf("less than or equal to %v", x) - - // Special case: make it clear that strings are strings. - if reflect.TypeOf(x).Kind() == reflect.String { - desc = fmt.Sprintf("less than or equal to \"%s\"", x) - } - - // Put LessThan last so that its error messages will be used in the event of - // failure. - return transformDescription(AnyOf(Equals(x), LessThan(x)), desc) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/less_than.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/less_than.go deleted file mode 100644 index 8258e45..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/less_than.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "math" - "reflect" -) - -// LessThan returns a matcher that matches integer, floating point, or strings -// values v such that v < x. Comparison is not defined between numeric and -// string types, but is defined between all integer and floating point types. -// -// x must itself be an integer, floating point, or string type; otherwise, -// LessThan will panic. -func LessThan(x interface{}) Matcher { - v := reflect.ValueOf(x) - kind := v.Kind() - - switch { - case isInteger(v): - case isFloat(v): - case kind == reflect.String: - - default: - panic(fmt.Sprintf("LessThan: unexpected kind %v", kind)) - } - - return &lessThanMatcher{v} -} - -type lessThanMatcher struct { - limit reflect.Value -} - -func (m *lessThanMatcher) Description() string { - // Special case: make it clear that strings are strings. - if m.limit.Kind() == reflect.String { - return fmt.Sprintf("less than \"%s\"", m.limit.String()) - } - - return fmt.Sprintf("less than %v", m.limit.Interface()) -} - -func compareIntegers(v1, v2 reflect.Value) (err error) { - err = errors.New("") - - switch { - case isSignedInteger(v1) && isSignedInteger(v2): - if v1.Int() < v2.Int() { - err = nil - } - return - - case isSignedInteger(v1) && isUnsignedInteger(v2): - if v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() { - err = nil - } - return - - case isUnsignedInteger(v1) && isSignedInteger(v2): - if v1.Uint() <= math.MaxInt64 && int64(v1.Uint()) < v2.Int() { - err = nil - } - return - - case isUnsignedInteger(v1) && isUnsignedInteger(v2): - if v1.Uint() < v2.Uint() { - err = nil - } - return - } - - panic(fmt.Sprintf("compareIntegers: %v %v", v1, v2)) -} - -func getFloat(v reflect.Value) float64 { - switch { - case isSignedInteger(v): - return float64(v.Int()) - - case isUnsignedInteger(v): - return float64(v.Uint()) - - case isFloat(v): - return v.Float() - } - - panic(fmt.Sprintf("getFloat: %v", v)) -} - -func (m *lessThanMatcher) Matches(c interface{}) (err error) { - v1 := reflect.ValueOf(c) - v2 := m.limit - - err = errors.New("") - - // Handle strings as a special case. - if v1.Kind() == reflect.String && v2.Kind() == reflect.String { - if v1.String() < v2.String() { - err = nil - } - return - } - - // If we get here, we require that we are dealing with integers or floats. - v1Legal := isInteger(v1) || isFloat(v1) - v2Legal := isInteger(v2) || isFloat(v2) - if !v1Legal || !v2Legal { - err = NewFatalError("which is not comparable") - return - } - - // Handle the various comparison cases. - switch { - // Both integers - case isInteger(v1) && isInteger(v2): - return compareIntegers(v1, v2) - - // At least one float32 - case v1.Kind() == reflect.Float32 || v2.Kind() == reflect.Float32: - if float32(getFloat(v1)) < float32(getFloat(v2)) { - err = nil - } - return - - // At least one float64 - case v1.Kind() == reflect.Float64 || v2.Kind() == reflect.Float64: - if getFloat(v1) < getFloat(v2) { - err = nil - } - return - } - - // We shouldn't get here. - panic(fmt.Sprintf("lessThanMatcher.Matches: Shouldn't get here: %v %v", v1, v2)) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/matcher.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/matcher.go deleted file mode 100644 index 78159a0..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/matcher.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package oglematchers provides a set of matchers useful in a testing or -// mocking framework. These matchers are inspired by and mostly compatible with -// Google Test for C++ and Google JS Test. -// -// This package is used by github.com/smartystreets/assertions/internal/ogletest and -// github.com/smartystreets/assertions/internal/oglemock, which may be more directly useful if you're not -// writing your own testing package or defining your own matchers. -package oglematchers - -// A Matcher is some predicate implicitly defining a set of values that it -// matches. For example, GreaterThan(17) matches all numeric values greater -// than 17, and HasSubstr("taco") matches all strings with the substring -// "taco". -// -// Matchers are typically exposed to tests via constructor functions like -// HasSubstr. In order to implement such a function you can either define your -// own matcher type or use NewMatcher. -type Matcher interface { - // Check whether the supplied value belongs to the the set defined by the - // matcher. Return a non-nil error if and only if it does not. - // - // The error describes why the value doesn't match. The error text is a - // relative clause that is suitable for being placed after the value. For - // example, a predicate that matches strings with a particular substring may, - // when presented with a numerical value, return the following error text: - // - // "which is not a string" - // - // Then the failure message may look like: - // - // Expected: has substring "taco" - // Actual: 17, which is not a string - // - // If the error is self-apparent based on the description of the matcher, the - // error text may be empty (but the error still non-nil). For example: - // - // Expected: 17 - // Actual: 19 - // - // If you are implementing a new matcher, see also the documentation on - // FatalError. - Matches(candidate interface{}) error - - // Description returns a string describing the property that values matching - // this matcher have, as a verb phrase where the subject is the value. For - // example, "is greather than 17" or "has substring "taco"". - Description() string -} - -// FatalError is an implementation of the error interface that may be returned -// from matchers, indicating the error should be propagated. Returning a -// *FatalError indicates that the matcher doesn't process values of the -// supplied type, or otherwise doesn't know how to handle the value. -// -// For example, if GreaterThan(17) returned false for the value "taco" without -// a fatal error, then Not(GreaterThan(17)) would return true. This is -// technically correct, but is surprising and may mask failures where the wrong -// sort of matcher is accidentally used. Instead, GreaterThan(17) can return a -// fatal error, which will be propagated by Not(). -type FatalError struct { - errorText string -} - -// NewFatalError creates a FatalError struct with the supplied error text. -func NewFatalError(s string) *FatalError { - return &FatalError{s} -} - -func (e *FatalError) Error() string { - return e.errorText -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go deleted file mode 100644 index 1ed63f3..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" - "regexp" -) - -// MatchesRegexp returns a matcher that matches strings and byte slices whose -// contents match the supplied regular expression. The semantics are those of -// regexp.Match. In particular, that means the match is not implicitly anchored -// to the ends of the string: MatchesRegexp("bar") will match "foo bar baz". -func MatchesRegexp(pattern string) Matcher { - re, err := regexp.Compile(pattern) - if err != nil { - panic("MatchesRegexp: " + err.Error()) - } - - return &matchesRegexpMatcher{re} -} - -type matchesRegexpMatcher struct { - re *regexp.Regexp -} - -func (m *matchesRegexpMatcher) Description() string { - return fmt.Sprintf("matches regexp \"%s\"", m.re.String()) -} - -func (m *matchesRegexpMatcher) Matches(c interface{}) (err error) { - v := reflect.ValueOf(c) - isString := v.Kind() == reflect.String - isByteSlice := v.Kind() == reflect.Slice && v.Elem().Kind() == reflect.Uint8 - - err = errors.New("") - - switch { - case isString: - if m.re.MatchString(v.String()) { - err = nil - } - - case isByteSlice: - if m.re.Match(v.Bytes()) { - err = nil - } - - default: - err = NewFatalError("which is not a string or []byte") - } - - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go deleted file mode 100644 index c9d8398..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -// Create a matcher with the given description and predicate function, which -// will be invoked to handle calls to Matchers. -// -// Using this constructor may be a convenience over defining your own type that -// implements Matcher if you do not need any logic in your Description method. -func NewMatcher( - predicate func(interface{}) error, - description string) Matcher { - return &predicateMatcher{ - predicate: predicate, - description: description, - } -} - -type predicateMatcher struct { - predicate func(interface{}) error - description string -} - -func (pm *predicateMatcher) Matches(c interface{}) error { - return pm.predicate(c) -} - -func (pm *predicateMatcher) Description() string { - return pm.description -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/not.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/not.go deleted file mode 100644 index 623789f..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/not.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" -) - -// Not returns a matcher that inverts the set of values matched by the wrapped -// matcher. It does not transform the result for values for which the wrapped -// matcher returns a fatal error. -func Not(m Matcher) Matcher { - return ¬Matcher{m} -} - -type notMatcher struct { - wrapped Matcher -} - -func (m *notMatcher) Matches(c interface{}) (err error) { - err = m.wrapped.Matches(c) - - // Did the wrapped matcher say yes? - if err == nil { - return errors.New("") - } - - // Did the wrapped matcher return a fatal error? - if _, isFatal := err.(*FatalError); isFatal { - return err - } - - // The wrapped matcher returned a non-fatal error. - return nil -} - -func (m *notMatcher) Description() string { - return fmt.Sprintf("not(%s)", m.wrapped.Description()) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go deleted file mode 100644 index d2cfc97..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" -) - -// Panics matches zero-arg functions which, when invoked, panic with an error -// that matches the supplied matcher. -// -// NOTE(jacobsa): This matcher cannot detect the case where the function panics -// using panic(nil), by design of the language. See here for more info: -// -// http://goo.gl/9aIQL -// -func Panics(m Matcher) Matcher { - return &panicsMatcher{m} -} - -type panicsMatcher struct { - wrappedMatcher Matcher -} - -func (m *panicsMatcher) Description() string { - return "panics with: " + m.wrappedMatcher.Description() -} - -func (m *panicsMatcher) Matches(c interface{}) (err error) { - // Make sure c is a zero-arg function. - v := reflect.ValueOf(c) - if v.Kind() != reflect.Func || v.Type().NumIn() != 0 { - err = NewFatalError("which is not a zero-arg function") - return - } - - // Call the function and check its panic error. - defer func() { - if e := recover(); e != nil { - err = m.wrappedMatcher.Matches(e) - - // Set a clearer error message if the matcher said no. - if err != nil { - wrappedClause := "" - if err.Error() != "" { - wrappedClause = ", " + err.Error() - } - - err = errors.New(fmt.Sprintf("which panicked with: %v%s", e, wrappedClause)) - } - } - }() - - v.Call([]reflect.Value{}) - - // If we get here, the function didn't panic. - err = errors.New("which didn't panic") - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go deleted file mode 100644 index c5383f2..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -import ( - "errors" - "fmt" - "reflect" -) - -// Return a matcher that matches non-nil pointers whose pointee matches the -// wrapped matcher. -func Pointee(m Matcher) Matcher { - return &pointeeMatcher{m} -} - -type pointeeMatcher struct { - wrapped Matcher -} - -func (m *pointeeMatcher) Matches(c interface{}) (err error) { - // Make sure the candidate is of the appropriate type. - cv := reflect.ValueOf(c) - if !cv.IsValid() || cv.Kind() != reflect.Ptr { - return NewFatalError("which is not a pointer") - } - - // Make sure the candidate is non-nil. - if cv.IsNil() { - return NewFatalError("") - } - - // Defer to the wrapped matcher. Fix up empty errors so that failure messages - // are more helpful than just printing a pointer for "Actual". - pointee := cv.Elem().Interface() - err = m.wrapped.Matches(pointee) - if err != nil && err.Error() == "" { - s := fmt.Sprintf("whose pointee is %v", pointee) - - if _, ok := err.(*FatalError); ok { - err = NewFatalError(s) - } else { - err = errors.New(s) - } - } - - return err -} - -func (m *pointeeMatcher) Description() string { - return fmt.Sprintf("pointee(%s)", m.wrapped.Description()) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go deleted file mode 100644 index f79d0c0..0000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oglematchers - -// transformDescription returns a matcher that is equivalent to the supplied -// one, except that it has the supplied description instead of the one attached -// to the existing matcher. -func transformDescription(m Matcher, newDesc string) Matcher { - return &transformDescriptionMatcher{newDesc, m} -} - -type transformDescriptionMatcher struct { - desc string - wrappedMatcher Matcher -} - -func (m *transformDescriptionMatcher) Description() string { - return m.desc -} - -func (m *transformDescriptionMatcher) Matches(c interface{}) error { - return m.wrappedMatcher.Matches(c) -} diff --git a/vendor/github.com/smartystreets/assertions/messages.go b/vendor/github.com/smartystreets/assertions/messages.go deleted file mode 100644 index 3188545..0000000 --- a/vendor/github.com/smartystreets/assertions/messages.go +++ /dev/null @@ -1,94 +0,0 @@ -package assertions - -const ( // equality - shouldHaveBeenEqual = "Expected: '%v'\nActual: '%v'\n(Should be equal)" - shouldNotHaveBeenEqual = "Expected '%v'\nto NOT equal '%v'\n(but it did)!" - shouldHaveBeenEqualTypeMismatch = "Expected: '%v' (%T)\nActual: '%v' (%T)\n(Should be equal, type mismatch)" - shouldHaveBeenAlmostEqual = "Expected '%v' to almost equal '%v' (but it didn't)!" - shouldHaveNotBeenAlmostEqual = "Expected '%v' to NOT almost equal '%v' (but it did)!" - shouldHaveResembled = "Expected: '%#v'\nActual: '%#v'\n(Should resemble)!" - shouldHaveResembledTypeMismatch = "Expected: '%#v' (%T)\nActual: '%#v' (%T)\n(Should resemble, type mismatch)" - shouldNotHaveResembled = "Expected '%#v'\nto NOT resemble '%#v'\n(but it did)!" - shouldBePointers = "Both arguments should be pointers " - shouldHaveBeenNonNilPointer = shouldBePointers + "(the %s was %s)!" - shouldHavePointedTo = "Expected '%+v' (address: '%v') and '%+v' (address: '%v') to be the same address (but their weren't)!" - shouldNotHavePointedTo = "Expected '%+v' and '%+v' to be different references (but they matched: '%v')!" - shouldHaveBeenNil = "Expected: nil\nActual: '%v'" - shouldNotHaveBeenNil = "Expected '%+v' to NOT be nil (but it was)!" - shouldHaveBeenTrue = "Expected: true\nActual: %v" - shouldHaveBeenFalse = "Expected: false\nActual: %v" - shouldHaveBeenZeroValue = "'%+v' should have been the zero value" //"Expected: (zero value)\nActual: %v" -) - -const ( // quantity comparisons - shouldHaveBeenGreater = "Expected '%v' to be greater than '%v' (but it wasn't)!" - shouldHaveBeenGreaterOrEqual = "Expected '%v' to be greater than or equal to '%v' (but it wasn't)!" - shouldHaveBeenLess = "Expected '%v' to be less than '%v' (but it wasn't)!" - shouldHaveBeenLessOrEqual = "Expected '%v' to be less than or equal to '%v' (but it wasn't)!" - shouldHaveBeenBetween = "Expected '%v' to be between '%v' and '%v' (but it wasn't)!" - shouldNotHaveBeenBetween = "Expected '%v' NOT to be between '%v' and '%v' (but it was)!" - shouldHaveDifferentUpperAndLower = "The lower and upper bounds must be different values (they were both '%v')." - shouldHaveBeenBetweenOrEqual = "Expected '%v' to be between '%v' and '%v' or equal to one of them (but it wasn't)!" - shouldNotHaveBeenBetweenOrEqual = "Expected '%v' NOT to be between '%v' and '%v' or equal to one of them (but it was)!" -) - -const ( // collections - shouldHaveContained = "Expected the container (%v) to contain: '%v' (but it didn't)!" - shouldNotHaveContained = "Expected the container (%v) NOT to contain: '%v' (but it did)!" - shouldHaveContainedKey = "Expected the %v to contain the key: %v (but it didn't)!" - shouldNotHaveContainedKey = "Expected the %v NOT to contain the key: %v (but it did)!" - shouldHaveBeenIn = "Expected '%v' to be in the container (%v), but it wasn't!" - shouldNotHaveBeenIn = "Expected '%v' NOT to be in the container (%v), but it was!" - shouldHaveBeenAValidCollection = "You must provide a valid container (was %v)!" - shouldHaveBeenAValidMap = "You must provide a valid map type (was %v)!" - shouldHaveBeenEmpty = "Expected %+v to be empty (but it wasn't)!" - shouldNotHaveBeenEmpty = "Expected %+v to NOT be empty (but it was)!" - shouldHaveBeenAValidInteger = "You must provide a valid integer (was %v)!" - shouldHaveBeenAValidLength = "You must provide a valid positive integer (was %v)!" - shouldHaveHadLength = "Expected %+v to have length equal to '%v', but it wasn't!" -) - -const ( // strings - shouldHaveStartedWith = "Expected '%v'\nto start with '%v'\n(but it didn't)!" - shouldNotHaveStartedWith = "Expected '%v'\nNOT to start with '%v'\n(but it did)!" - shouldHaveEndedWith = "Expected '%v'\nto end with '%v'\n(but it didn't)!" - shouldNotHaveEndedWith = "Expected '%v'\nNOT to end with '%v'\n(but it did)!" - shouldAllBeStrings = "All arguments to this assertion must be strings (you provided: %v)." - shouldBothBeStrings = "Both arguments to this assertion must be strings (you provided %v and %v)." - shouldBeString = "The argument to this assertion must be a string (you provided %v)." - shouldHaveContainedSubstring = "Expected '%s' to contain substring '%s' (but it didn't)!" - shouldNotHaveContainedSubstring = "Expected '%s' NOT to contain substring '%s' (but it did)!" - shouldHaveBeenBlank = "Expected '%s' to be blank (but it wasn't)!" - shouldNotHaveBeenBlank = "Expected value to NOT be blank (but it was)!" -) - -const ( // panics - shouldUseVoidNiladicFunction = "You must provide a void, niladic function as the first argument!" - shouldHavePanickedWith = "Expected func() to panic with '%v' (but it panicked with '%v')!" - shouldHavePanicked = "Expected func() to panic (but it didn't)!" - shouldNotHavePanicked = "Expected func() NOT to panic (error: '%+v')!" - shouldNotHavePanickedWith = "Expected func() NOT to panic with '%v' (but it did)!" -) - -const ( // type checking - shouldHaveBeenA = "Expected '%v' to be: '%v' (but was: '%v')!" - shouldNotHaveBeenA = "Expected '%v' to NOT be: '%v' (but it was)!" - - shouldHaveImplemented = "Expected: '%v interface support'\nActual: '%v' does not implement the interface!" - shouldNotHaveImplemented = "Expected '%v'\nto NOT implement '%v'\n(but it did)!" - shouldCompareWithInterfacePointer = "The expected value must be a pointer to an interface type (eg. *fmt.Stringer)" - shouldNotBeNilActual = "The actual value was 'nil' and should be a value or a pointer to a value!" -) - -const ( // time comparisons - shouldUseTimes = "You must provide time instances as arguments to this assertion." - shouldUseTimeSlice = "You must provide a slice of time instances as the first argument to this assertion." - shouldUseDurationAndTime = "You must provide a duration and a time as arguments to this assertion." - shouldHaveHappenedBefore = "Expected '%v' to happen before '%v' (it happened '%v' after)!" - shouldHaveHappenedAfter = "Expected '%v' to happen after '%v' (it happened '%v' before)!" - shouldHaveHappenedBetween = "Expected '%v' to happen between '%v' and '%v' (it happened '%v' outside threshold)!" - shouldNotHaveHappenedOnOrBetween = "Expected '%v' to NOT happen on or between '%v' and '%v' (but it did)!" - - // format params: incorrect-index, previous-index, previous-time, incorrect-index, incorrect-time - shouldHaveBeenChronological = "The 'Time' at index [%d] should have happened after the previous one (but it didn't!):\n [%d]: %s\n [%d]: %s (see, it happened before!)" -) diff --git a/vendor/github.com/smartystreets/assertions/panic.go b/vendor/github.com/smartystreets/assertions/panic.go deleted file mode 100644 index 7e75db1..0000000 --- a/vendor/github.com/smartystreets/assertions/panic.go +++ /dev/null @@ -1,115 +0,0 @@ -package assertions - -import "fmt" - -// ShouldPanic receives a void, niladic function and expects to recover a panic. -func ShouldPanic(actual interface{}, expected ...interface{}) (message string) { - if fail := need(0, expected); fail != success { - return fail - } - - action, _ := actual.(func()) - - if action == nil { - message = shouldUseVoidNiladicFunction - return - } - - defer func() { - recovered := recover() - if recovered == nil { - message = shouldHavePanicked - } else { - message = success - } - }() - action() - - return -} - -// ShouldNotPanic receives a void, niladic function and expects to execute the function without any panic. -func ShouldNotPanic(actual interface{}, expected ...interface{}) (message string) { - if fail := need(0, expected); fail != success { - return fail - } - - action, _ := actual.(func()) - - if action == nil { - message = shouldUseVoidNiladicFunction - return - } - - defer func() { - recovered := recover() - if recovered != nil { - message = fmt.Sprintf(shouldNotHavePanicked, recovered) - } else { - message = success - } - }() - action() - - return -} - -// ShouldPanicWith receives a void, niladic function and expects to recover a panic with the second argument as the content. -func ShouldPanicWith(actual interface{}, expected ...interface{}) (message string) { - if fail := need(1, expected); fail != success { - return fail - } - - action, _ := actual.(func()) - - if action == nil { - message = shouldUseVoidNiladicFunction - return - } - - defer func() { - recovered := recover() - if recovered == nil { - message = shouldHavePanicked - } else { - if equal := ShouldEqual(recovered, expected[0]); equal != success { - message = serializer.serialize(expected[0], recovered, fmt.Sprintf(shouldHavePanickedWith, expected[0], recovered)) - } else { - message = success - } - } - }() - action() - - return -} - -// ShouldNotPanicWith receives a void, niladic function and expects to recover a panic whose content differs from the second argument. -func ShouldNotPanicWith(actual interface{}, expected ...interface{}) (message string) { - if fail := need(1, expected); fail != success { - return fail - } - - action, _ := actual.(func()) - - if action == nil { - message = shouldUseVoidNiladicFunction - return - } - - defer func() { - recovered := recover() - if recovered == nil { - message = success - } else { - if equal := ShouldEqual(recovered, expected[0]); equal == success { - message = fmt.Sprintf(shouldNotHavePanickedWith, expected[0]) - } else { - message = success - } - } - }() - action() - - return -} diff --git a/vendor/github.com/smartystreets/assertions/quantity.go b/vendor/github.com/smartystreets/assertions/quantity.go deleted file mode 100644 index 80789f0..0000000 --- a/vendor/github.com/smartystreets/assertions/quantity.go +++ /dev/null @@ -1,141 +0,0 @@ -package assertions - -import ( - "fmt" - - "github.com/smartystreets/assertions/internal/oglematchers" -) - -// ShouldBeGreaterThan receives exactly two parameters and ensures that the first is greater than the second. -func ShouldBeGreaterThan(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - if matchError := oglematchers.GreaterThan(expected[0]).Matches(actual); matchError != nil { - return fmt.Sprintf(shouldHaveBeenGreater, actual, expected[0]) - } - return success -} - -// ShouldBeGreaterThanOrEqualTo receives exactly two parameters and ensures that the first is greater than or equal to the second. -func ShouldBeGreaterThanOrEqualTo(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } else if matchError := oglematchers.GreaterOrEqual(expected[0]).Matches(actual); matchError != nil { - return fmt.Sprintf(shouldHaveBeenGreaterOrEqual, actual, expected[0]) - } - return success -} - -// ShouldBeLessThan receives exactly two parameters and ensures that the first is less than the second. -func ShouldBeLessThan(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } else if matchError := oglematchers.LessThan(expected[0]).Matches(actual); matchError != nil { - return fmt.Sprintf(shouldHaveBeenLess, actual, expected[0]) - } - return success -} - -// ShouldBeLessThan receives exactly two parameters and ensures that the first is less than or equal to the second. -func ShouldBeLessThanOrEqualTo(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } else if matchError := oglematchers.LessOrEqual(expected[0]).Matches(actual); matchError != nil { - return fmt.Sprintf(shouldHaveBeenLess, actual, expected[0]) - } - return success -} - -// ShouldBeBetween receives exactly three parameters: an actual value, a lower bound, and an upper bound. -// It ensures that the actual value is between both bounds (but not equal to either of them). -func ShouldBeBetween(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - lower, upper, fail := deriveBounds(expected) - - if fail != success { - return fail - } else if !isBetween(actual, lower, upper) { - return fmt.Sprintf(shouldHaveBeenBetween, actual, lower, upper) - } - return success -} - -// ShouldNotBeBetween receives exactly three parameters: an actual value, a lower bound, and an upper bound. -// It ensures that the actual value is NOT between both bounds. -func ShouldNotBeBetween(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - lower, upper, fail := deriveBounds(expected) - - if fail != success { - return fail - } else if isBetween(actual, lower, upper) { - return fmt.Sprintf(shouldNotHaveBeenBetween, actual, lower, upper) - } - return success -} -func deriveBounds(values []interface{}) (lower interface{}, upper interface{}, fail string) { - lower = values[0] - upper = values[1] - - if ShouldNotEqual(lower, upper) != success { - return nil, nil, fmt.Sprintf(shouldHaveDifferentUpperAndLower, lower) - } else if ShouldBeLessThan(lower, upper) != success { - lower, upper = upper, lower - } - return lower, upper, success -} -func isBetween(value, lower, upper interface{}) bool { - if ShouldBeGreaterThan(value, lower) != success { - return false - } else if ShouldBeLessThan(value, upper) != success { - return false - } - return true -} - -// ShouldBeBetweenOrEqual receives exactly three parameters: an actual value, a lower bound, and an upper bound. -// It ensures that the actual value is between both bounds or equal to one of them. -func ShouldBeBetweenOrEqual(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - lower, upper, fail := deriveBounds(expected) - - if fail != success { - return fail - } else if !isBetweenOrEqual(actual, lower, upper) { - return fmt.Sprintf(shouldHaveBeenBetweenOrEqual, actual, lower, upper) - } - return success -} - -// ShouldNotBeBetweenOrEqual receives exactly three parameters: an actual value, a lower bound, and an upper bound. -// It ensures that the actual value is nopt between the bounds nor equal to either of them. -func ShouldNotBeBetweenOrEqual(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - lower, upper, fail := deriveBounds(expected) - - if fail != success { - return fail - } else if isBetweenOrEqual(actual, lower, upper) { - return fmt.Sprintf(shouldNotHaveBeenBetweenOrEqual, actual, lower, upper) - } - return success -} - -func isBetweenOrEqual(value, lower, upper interface{}) bool { - if ShouldBeGreaterThanOrEqualTo(value, lower) != success { - return false - } else if ShouldBeLessThanOrEqualTo(value, upper) != success { - return false - } - return true -} diff --git a/vendor/github.com/smartystreets/assertions/serializer.go b/vendor/github.com/smartystreets/assertions/serializer.go deleted file mode 100644 index 90c4ae3..0000000 --- a/vendor/github.com/smartystreets/assertions/serializer.go +++ /dev/null @@ -1,59 +0,0 @@ -package assertions - -import ( - "encoding/json" - "fmt" - - "github.com/smartystreets/goconvey/convey/reporting" -) - -type Serializer interface { - serialize(expected, actual interface{}, message string) string - serializeDetailed(expected, actual interface{}, message string) string -} - -type failureSerializer struct{} - -func (self *failureSerializer) serializeDetailed(expected, actual interface{}, message string) string { - view := self.format(expected, actual, message, "%#v") - serialized, err := json.Marshal(view) - if err != nil { - return message - } - return string(serialized) -} - -func (self *failureSerializer) serialize(expected, actual interface{}, message string) string { - view := self.format(expected, actual, message, "%+v") - serialized, err := json.Marshal(view) - if err != nil { - return message - } - return string(serialized) -} - -func (self *failureSerializer) format(expected, actual interface{}, message string, format string) reporting.FailureView { - return reporting.FailureView{ - Message: message, - Expected: fmt.Sprintf(format, expected), - Actual: fmt.Sprintf(format, actual), - } -} - -func newSerializer() *failureSerializer { - return &failureSerializer{} -} - -/////////////////////////////////////////////////////// - -// noopSerializer just gives back the original message. This is useful when we are using -// the assertions from a context other than the web UI, that requires the JSON structure -// provided by the failureSerializer. -type noopSerializer struct{} - -func (self *noopSerializer) serialize(expected, actual interface{}, message string) string { - return message -} -func (self *noopSerializer) serializeDetailed(expected, actual interface{}, message string) string { - return message -} diff --git a/vendor/github.com/smartystreets/assertions/strings.go b/vendor/github.com/smartystreets/assertions/strings.go deleted file mode 100644 index dbc3f04..0000000 --- a/vendor/github.com/smartystreets/assertions/strings.go +++ /dev/null @@ -1,227 +0,0 @@ -package assertions - -import ( - "fmt" - "reflect" - "strings" -) - -// ShouldStartWith receives exactly 2 string parameters and ensures that the first starts with the second. -func ShouldStartWith(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - value, valueIsString := actual.(string) - prefix, prefixIsString := expected[0].(string) - - if !valueIsString || !prefixIsString { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - return shouldStartWith(value, prefix) -} -func shouldStartWith(value, prefix string) string { - if !strings.HasPrefix(value, prefix) { - shortval := value - if len(shortval) > len(prefix) { - shortval = shortval[:len(prefix)] + "..." - } - return serializer.serialize(prefix, shortval, fmt.Sprintf(shouldHaveStartedWith, value, prefix)) - } - return success -} - -// ShouldNotStartWith receives exactly 2 string parameters and ensures that the first does not start with the second. -func ShouldNotStartWith(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - value, valueIsString := actual.(string) - prefix, prefixIsString := expected[0].(string) - - if !valueIsString || !prefixIsString { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - return shouldNotStartWith(value, prefix) -} -func shouldNotStartWith(value, prefix string) string { - if strings.HasPrefix(value, prefix) { - if value == "" { - value = "" - } - if prefix == "" { - prefix = "" - } - return fmt.Sprintf(shouldNotHaveStartedWith, value, prefix) - } - return success -} - -// ShouldEndWith receives exactly 2 string parameters and ensures that the first ends with the second. -func ShouldEndWith(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - value, valueIsString := actual.(string) - suffix, suffixIsString := expected[0].(string) - - if !valueIsString || !suffixIsString { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - return shouldEndWith(value, suffix) -} -func shouldEndWith(value, suffix string) string { - if !strings.HasSuffix(value, suffix) { - shortval := value - if len(shortval) > len(suffix) { - shortval = "..." + shortval[len(shortval)-len(suffix):] - } - return serializer.serialize(suffix, shortval, fmt.Sprintf(shouldHaveEndedWith, value, suffix)) - } - return success -} - -// ShouldEndWith receives exactly 2 string parameters and ensures that the first does not end with the second. -func ShouldNotEndWith(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - value, valueIsString := actual.(string) - suffix, suffixIsString := expected[0].(string) - - if !valueIsString || !suffixIsString { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - return shouldNotEndWith(value, suffix) -} -func shouldNotEndWith(value, suffix string) string { - if strings.HasSuffix(value, suffix) { - if value == "" { - value = "" - } - if suffix == "" { - suffix = "" - } - return fmt.Sprintf(shouldNotHaveEndedWith, value, suffix) - } - return success -} - -// ShouldContainSubstring receives exactly 2 string parameters and ensures that the first contains the second as a substring. -func ShouldContainSubstring(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - long, longOk := actual.(string) - short, shortOk := expected[0].(string) - - if !longOk || !shortOk { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - if !strings.Contains(long, short) { - return serializer.serialize(expected[0], actual, fmt.Sprintf(shouldHaveContainedSubstring, long, short)) - } - return success -} - -// ShouldNotContainSubstring receives exactly 2 string parameters and ensures that the first does NOT contain the second as a substring. -func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - long, longOk := actual.(string) - short, shortOk := expected[0].(string) - - if !longOk || !shortOk { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - if strings.Contains(long, short) { - return fmt.Sprintf(shouldNotHaveContainedSubstring, long, short) - } - return success -} - -// ShouldBeBlank receives exactly 1 string parameter and ensures that it is equal to "". -func ShouldBeBlank(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } - value, ok := actual.(string) - if !ok { - return fmt.Sprintf(shouldBeString, reflect.TypeOf(actual)) - } - if value != "" { - return serializer.serialize("", value, fmt.Sprintf(shouldHaveBeenBlank, value)) - } - return success -} - -// ShouldNotBeBlank receives exactly 1 string parameter and ensures that it is equal to "". -func ShouldNotBeBlank(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } - value, ok := actual.(string) - if !ok { - return fmt.Sprintf(shouldBeString, reflect.TypeOf(actual)) - } - if value == "" { - return shouldNotHaveBeenBlank - } - return success -} - -// ShouldEqualWithout receives exactly 3 string parameters and ensures that the first is equal to the second -// after removing all instances of the third from the first using strings.Replace(first, third, "", -1). -func ShouldEqualWithout(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - actualString, ok1 := actual.(string) - expectedString, ok2 := expected[0].(string) - replace, ok3 := expected[1].(string) - - if !ok1 || !ok2 || !ok3 { - return fmt.Sprintf(shouldAllBeStrings, []reflect.Type{ - reflect.TypeOf(actual), - reflect.TypeOf(expected[0]), - reflect.TypeOf(expected[1]), - }) - } - - replaced := strings.Replace(actualString, replace, "", -1) - if replaced == expectedString { - return "" - } - - return fmt.Sprintf("Expected '%s' to equal '%s' but without any '%s' (but it didn't).", actualString, expectedString, replace) -} - -// ShouldEqualTrimSpace receives exactly 2 string parameters and ensures that the first is equal to the second -// after removing all leading and trailing whitespace using strings.TrimSpace(first). -func ShouldEqualTrimSpace(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - actualString, valueIsString := actual.(string) - _, value2IsString := expected[0].(string) - - if !valueIsString || !value2IsString { - return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0])) - } - - actualString = strings.TrimSpace(actualString) - return ShouldEqual(actualString, expected[0]) -} diff --git a/vendor/github.com/smartystreets/assertions/time.go b/vendor/github.com/smartystreets/assertions/time.go deleted file mode 100644 index 7e05026..0000000 --- a/vendor/github.com/smartystreets/assertions/time.go +++ /dev/null @@ -1,202 +0,0 @@ -package assertions - -import ( - "fmt" - "time" -) - -// ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the first happens before the second. -func ShouldHappenBefore(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - expectedTime, secondOk := expected[0].(time.Time) - - if !firstOk || !secondOk { - return shouldUseTimes - } - - if !actualTime.Before(expectedTime) { - return fmt.Sprintf(shouldHaveHappenedBefore, actualTime, expectedTime, actualTime.Sub(expectedTime)) - } - - return success -} - -// ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that the first happens on or before the second. -func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - expectedTime, secondOk := expected[0].(time.Time) - - if !firstOk || !secondOk { - return shouldUseTimes - } - - if actualTime.Equal(expectedTime) { - return success - } - return ShouldHappenBefore(actualTime, expectedTime) -} - -// ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the first happens after the second. -func ShouldHappenAfter(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - expectedTime, secondOk := expected[0].(time.Time) - - if !firstOk || !secondOk { - return shouldUseTimes - } - if !actualTime.After(expectedTime) { - return fmt.Sprintf(shouldHaveHappenedAfter, actualTime, expectedTime, expectedTime.Sub(actualTime)) - } - return success -} - -// ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that the first happens on or after the second. -func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - expectedTime, secondOk := expected[0].(time.Time) - - if !firstOk || !secondOk { - return shouldUseTimes - } - if actualTime.Equal(expectedTime) { - return success - } - return ShouldHappenAfter(actualTime, expectedTime) -} - -// ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the first happens between (not on) the second and third. -func ShouldHappenBetween(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - min, secondOk := expected[0].(time.Time) - max, thirdOk := expected[1].(time.Time) - - if !firstOk || !secondOk || !thirdOk { - return shouldUseTimes - } - - if !actualTime.After(min) { - return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, min.Sub(actualTime)) - } - if !actualTime.Before(max) { - return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, actualTime.Sub(max)) - } - return success -} - -// ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first happens between or on the second and third. -func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - min, secondOk := expected[0].(time.Time) - max, thirdOk := expected[1].(time.Time) - - if !firstOk || !secondOk || !thirdOk { - return shouldUseTimes - } - if actualTime.Equal(min) || actualTime.Equal(max) { - return success - } - return ShouldHappenBetween(actualTime, min, max) -} - -// ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first -// does NOT happen between or on the second or third. -func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - min, secondOk := expected[0].(time.Time) - max, thirdOk := expected[1].(time.Time) - - if !firstOk || !secondOk || !thirdOk { - return shouldUseTimes - } - if actualTime.Equal(min) || actualTime.Equal(max) { - return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max) - } - if actualTime.After(min) && actualTime.Before(max) { - return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max) - } - return success -} - -// ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments) -// and asserts that the first time.Time happens within or on the duration specified relative to -// the other time.Time. -func ShouldHappenWithin(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - tolerance, secondOk := expected[0].(time.Duration) - threshold, thirdOk := expected[1].(time.Time) - - if !firstOk || !secondOk || !thirdOk { - return shouldUseDurationAndTime - } - - min := threshold.Add(-tolerance) - max := threshold.Add(tolerance) - return ShouldHappenOnOrBetween(actualTime, min, max) -} - -// ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments) -// and asserts that the first time.Time does NOT happen within or on the duration specified relative to -// the other time.Time. -func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string { - if fail := need(2, expected); fail != success { - return fail - } - actualTime, firstOk := actual.(time.Time) - tolerance, secondOk := expected[0].(time.Duration) - threshold, thirdOk := expected[1].(time.Time) - - if !firstOk || !secondOk || !thirdOk { - return shouldUseDurationAndTime - } - - min := threshold.Add(-tolerance) - max := threshold.Add(tolerance) - return ShouldNotHappenOnOrBetween(actualTime, min, max) -} - -// ShouldBeChronological receives a []time.Time slice and asserts that the are -// in chronological order starting with the first time.Time as the earliest. -func ShouldBeChronological(actual interface{}, expected ...interface{}) string { - if fail := need(0, expected); fail != success { - return fail - } - - times, ok := actual.([]time.Time) - if !ok { - return shouldUseTimeSlice - } - - var previous time.Time - for i, current := range times { - if i > 0 && current.Before(previous) { - return fmt.Sprintf(shouldHaveBeenChronological, - i, i-1, previous.String(), i, current.String()) - } - previous = current - } - return "" -} diff --git a/vendor/github.com/smartystreets/assertions/type.go b/vendor/github.com/smartystreets/assertions/type.go deleted file mode 100644 index 3fc00f6..0000000 --- a/vendor/github.com/smartystreets/assertions/type.go +++ /dev/null @@ -1,112 +0,0 @@ -package assertions - -import ( - "fmt" - "reflect" -) - -// ShouldHaveSameTypeAs receives exactly two parameters and compares their underlying types for equality. -func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - first := reflect.TypeOf(actual) - second := reflect.TypeOf(expected[0]) - - if equal := ShouldEqual(first, second); equal != success { - return serializer.serialize(second, first, fmt.Sprintf(shouldHaveBeenA, actual, second, first)) - } - return success -} - -// ShouldNotHaveSameTypeAs receives exactly two parameters and compares their underlying types for inequality. -func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string { - if fail := need(1, expected); fail != success { - return fail - } - - first := reflect.TypeOf(actual) - second := reflect.TypeOf(expected[0]) - - if equal := ShouldEqual(first, second); equal == success { - return fmt.Sprintf(shouldNotHaveBeenA, actual, second) - } - return success -} - -// ShouldImplement receives exactly two parameters and ensures -// that the first implements the interface type of the second. -func ShouldImplement(actual interface{}, expectedList ...interface{}) string { - if fail := need(1, expectedList); fail != success { - return fail - } - - expected := expectedList[0] - if fail := ShouldBeNil(expected); fail != success { - return shouldCompareWithInterfacePointer - } - - if fail := ShouldNotBeNil(actual); fail != success { - return shouldNotBeNilActual - } - - var actualType reflect.Type - if reflect.TypeOf(actual).Kind() != reflect.Ptr { - actualType = reflect.PtrTo(reflect.TypeOf(actual)) - } else { - actualType = reflect.TypeOf(actual) - } - - expectedType := reflect.TypeOf(expected) - if fail := ShouldNotBeNil(expectedType); fail != success { - return shouldCompareWithInterfacePointer - } - - expectedInterface := expectedType.Elem() - - if actualType == nil { - return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actual) - } - - if !actualType.Implements(expectedInterface) { - return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actualType) - } - return success -} - -// ShouldNotImplement receives exactly two parameters and ensures -// that the first does NOT implement the interface type of the second. -func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string { - if fail := need(1, expectedList); fail != success { - return fail - } - - expected := expectedList[0] - if fail := ShouldBeNil(expected); fail != success { - return shouldCompareWithInterfacePointer - } - - if fail := ShouldNotBeNil(actual); fail != success { - return shouldNotBeNilActual - } - - var actualType reflect.Type - if reflect.TypeOf(actual).Kind() != reflect.Ptr { - actualType = reflect.PtrTo(reflect.TypeOf(actual)) - } else { - actualType = reflect.TypeOf(actual) - } - - expectedType := reflect.TypeOf(expected) - if fail := ShouldNotBeNil(expectedType); fail != success { - return shouldCompareWithInterfacePointer - } - - expectedInterface := expectedType.Elem() - - if actualType.Implements(expectedInterface) { - return fmt.Sprintf(shouldNotHaveImplemented, actualType, expectedInterface) - } - return success -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/assertions.go b/vendor/github.com/smartystreets/goconvey/convey/assertions.go deleted file mode 100644 index 1e87b82..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/assertions.go +++ /dev/null @@ -1,68 +0,0 @@ -package convey - -import "github.com/smartystreets/assertions" - -var ( - ShouldEqual = assertions.ShouldEqual - ShouldNotEqual = assertions.ShouldNotEqual - ShouldAlmostEqual = assertions.ShouldAlmostEqual - ShouldNotAlmostEqual = assertions.ShouldNotAlmostEqual - ShouldResemble = assertions.ShouldResemble - ShouldNotResemble = assertions.ShouldNotResemble - ShouldPointTo = assertions.ShouldPointTo - ShouldNotPointTo = assertions.ShouldNotPointTo - ShouldBeNil = assertions.ShouldBeNil - ShouldNotBeNil = assertions.ShouldNotBeNil - ShouldBeTrue = assertions.ShouldBeTrue - ShouldBeFalse = assertions.ShouldBeFalse - ShouldBeZeroValue = assertions.ShouldBeZeroValue - - ShouldBeGreaterThan = assertions.ShouldBeGreaterThan - ShouldBeGreaterThanOrEqualTo = assertions.ShouldBeGreaterThanOrEqualTo - ShouldBeLessThan = assertions.ShouldBeLessThan - ShouldBeLessThanOrEqualTo = assertions.ShouldBeLessThanOrEqualTo - ShouldBeBetween = assertions.ShouldBeBetween - ShouldNotBeBetween = assertions.ShouldNotBeBetween - ShouldBeBetweenOrEqual = assertions.ShouldBeBetweenOrEqual - ShouldNotBeBetweenOrEqual = assertions.ShouldNotBeBetweenOrEqual - - ShouldContain = assertions.ShouldContain - ShouldNotContain = assertions.ShouldNotContain - ShouldContainKey = assertions.ShouldContainKey - ShouldNotContainKey = assertions.ShouldNotContainKey - ShouldBeIn = assertions.ShouldBeIn - ShouldNotBeIn = assertions.ShouldNotBeIn - ShouldBeEmpty = assertions.ShouldBeEmpty - ShouldNotBeEmpty = assertions.ShouldNotBeEmpty - ShouldHaveLength = assertions.ShouldHaveLength - - ShouldStartWith = assertions.ShouldStartWith - ShouldNotStartWith = assertions.ShouldNotStartWith - ShouldEndWith = assertions.ShouldEndWith - ShouldNotEndWith = assertions.ShouldNotEndWith - ShouldBeBlank = assertions.ShouldBeBlank - ShouldNotBeBlank = assertions.ShouldNotBeBlank - ShouldContainSubstring = assertions.ShouldContainSubstring - ShouldNotContainSubstring = assertions.ShouldNotContainSubstring - - ShouldPanic = assertions.ShouldPanic - ShouldNotPanic = assertions.ShouldNotPanic - ShouldPanicWith = assertions.ShouldPanicWith - ShouldNotPanicWith = assertions.ShouldNotPanicWith - - ShouldHaveSameTypeAs = assertions.ShouldHaveSameTypeAs - ShouldNotHaveSameTypeAs = assertions.ShouldNotHaveSameTypeAs - ShouldImplement = assertions.ShouldImplement - ShouldNotImplement = assertions.ShouldNotImplement - - ShouldHappenBefore = assertions.ShouldHappenBefore - ShouldHappenOnOrBefore = assertions.ShouldHappenOnOrBefore - ShouldHappenAfter = assertions.ShouldHappenAfter - ShouldHappenOnOrAfter = assertions.ShouldHappenOnOrAfter - ShouldHappenBetween = assertions.ShouldHappenBetween - ShouldHappenOnOrBetween = assertions.ShouldHappenOnOrBetween - ShouldNotHappenOnOrBetween = assertions.ShouldNotHappenOnOrBetween - ShouldHappenWithin = assertions.ShouldHappenWithin - ShouldNotHappenWithin = assertions.ShouldNotHappenWithin - ShouldBeChronological = assertions.ShouldBeChronological -) diff --git a/vendor/github.com/smartystreets/goconvey/convey/context.go b/vendor/github.com/smartystreets/goconvey/convey/context.go deleted file mode 100644 index 2c75c2d..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/context.go +++ /dev/null @@ -1,272 +0,0 @@ -package convey - -import ( - "fmt" - - "github.com/jtolds/gls" - "github.com/smartystreets/goconvey/convey/reporting" -) - -type conveyErr struct { - fmt string - params []interface{} -} - -func (e *conveyErr) Error() string { - return fmt.Sprintf(e.fmt, e.params...) -} - -func conveyPanic(fmt string, params ...interface{}) { - panic(&conveyErr{fmt, params}) -} - -const ( - missingGoTest = `Top-level calls to Convey(...) need a reference to the *testing.T. - Hint: Convey("description here", t, func() { /* notice that the second argument was the *testing.T (t)! */ }) ` - extraGoTest = `Only the top-level call to Convey(...) needs a reference to the *testing.T.` - noStackContext = "Convey operation made without context on goroutine stack.\n" + - "Hint: Perhaps you meant to use `Convey(..., func(c C){...})` ?" - differentConveySituations = "Different set of Convey statements on subsequent pass!\nDid not expect %#v." - multipleIdenticalConvey = "Multiple convey suites with identical names: %#v" -) - -const ( - failureHalt = "___FAILURE_HALT___" - - nodeKey = "node" -) - -///////////////////////////////// Stack Context ///////////////////////////////// - -func getCurrentContext() *context { - ctx, ok := ctxMgr.GetValue(nodeKey) - if ok { - return ctx.(*context) - } - return nil -} - -func mustGetCurrentContext() *context { - ctx := getCurrentContext() - if ctx == nil { - conveyPanic(noStackContext) - } - return ctx -} - -//////////////////////////////////// Context //////////////////////////////////// - -// context magically handles all coordination of Convey's and So assertions. -// -// It is tracked on the stack as goroutine-local-storage with the gls package, -// or explicitly if the user decides to call convey like: -// -// Convey(..., func(c C) { -// c.So(...) -// }) -// -// This implements the `C` interface. -type context struct { - reporter reporting.Reporter - - children map[string]*context - - resets []func() - - executedOnce bool - expectChildRun *bool - complete bool - - focus bool - failureMode FailureMode -} - -// rootConvey is the main entry point to a test suite. This is called when -// there's no context in the stack already, and items must contain a `t` object, -// or this panics. -func rootConvey(items ...interface{}) { - entry := discover(items) - - if entry.Test == nil { - conveyPanic(missingGoTest) - } - - expectChildRun := true - ctx := &context{ - reporter: buildReporter(), - - children: make(map[string]*context), - - expectChildRun: &expectChildRun, - - focus: entry.Focus, - failureMode: defaultFailureMode.combine(entry.FailMode), - } - ctxMgr.SetValues(gls.Values{nodeKey: ctx}, func() { - ctx.reporter.BeginStory(reporting.NewStoryReport(entry.Test)) - defer ctx.reporter.EndStory() - - for ctx.shouldVisit() { - ctx.conveyInner(entry.Situation, entry.Func) - expectChildRun = true - } - }) -} - -//////////////////////////////////// Methods //////////////////////////////////// - -func (ctx *context) SkipConvey(items ...interface{}) { - ctx.Convey(items, skipConvey) -} - -func (ctx *context) FocusConvey(items ...interface{}) { - ctx.Convey(items, focusConvey) -} - -func (ctx *context) Convey(items ...interface{}) { - entry := discover(items) - - // we're a branch, or leaf (on the wind) - if entry.Test != nil { - conveyPanic(extraGoTest) - } - if ctx.focus && !entry.Focus { - return - } - - var inner_ctx *context - if ctx.executedOnce { - var ok bool - inner_ctx, ok = ctx.children[entry.Situation] - if !ok { - conveyPanic(differentConveySituations, entry.Situation) - } - } else { - if _, ok := ctx.children[entry.Situation]; ok { - conveyPanic(multipleIdenticalConvey, entry.Situation) - } - inner_ctx = &context{ - reporter: ctx.reporter, - - children: make(map[string]*context), - - expectChildRun: ctx.expectChildRun, - - focus: entry.Focus, - failureMode: ctx.failureMode.combine(entry.FailMode), - } - ctx.children[entry.Situation] = inner_ctx - } - - if inner_ctx.shouldVisit() { - ctxMgr.SetValues(gls.Values{nodeKey: inner_ctx}, func() { - inner_ctx.conveyInner(entry.Situation, entry.Func) - }) - } -} - -func (ctx *context) SkipSo(stuff ...interface{}) { - ctx.assertionReport(reporting.NewSkipReport()) -} - -func (ctx *context) So(actual interface{}, assert assertion, expected ...interface{}) { - if result := assert(actual, expected...); result == assertionSuccess { - ctx.assertionReport(reporting.NewSuccessReport()) - } else { - ctx.assertionReport(reporting.NewFailureReport(result)) - } -} - -func (ctx *context) Reset(action func()) { - /* TODO: Failure mode configuration */ - ctx.resets = append(ctx.resets, action) -} - -func (ctx *context) Print(items ...interface{}) (int, error) { - fmt.Fprint(ctx.reporter, items...) - return fmt.Print(items...) -} - -func (ctx *context) Println(items ...interface{}) (int, error) { - fmt.Fprintln(ctx.reporter, items...) - return fmt.Println(items...) -} - -func (ctx *context) Printf(format string, items ...interface{}) (int, error) { - fmt.Fprintf(ctx.reporter, format, items...) - return fmt.Printf(format, items...) -} - -//////////////////////////////////// Private //////////////////////////////////// - -// shouldVisit returns true iff we should traverse down into a Convey. Note -// that just because we don't traverse a Convey this time, doesn't mean that -// we may not traverse it on a subsequent pass. -func (c *context) shouldVisit() bool { - return !c.complete && *c.expectChildRun -} - -// conveyInner is the function which actually executes the user's anonymous test -// function body. At this point, Convey or RootConvey has decided that this -// function should actually run. -func (ctx *context) conveyInner(situation string, f func(C)) { - // Record/Reset state for next time. - defer func() { - ctx.executedOnce = true - - // This is only needed at the leaves, but there's no harm in also setting it - // when returning from branch Convey's - *ctx.expectChildRun = false - }() - - // Set up+tear down our scope for the reporter - ctx.reporter.Enter(reporting.NewScopeReport(situation)) - defer ctx.reporter.Exit() - - // Recover from any panics in f, and assign the `complete` status for this - // node of the tree. - defer func() { - ctx.complete = true - if problem := recover(); problem != nil { - if problem, ok := problem.(*conveyErr); ok { - panic(problem) - } - if problem != failureHalt { - ctx.reporter.Report(reporting.NewErrorReport(problem)) - } - } else { - for _, child := range ctx.children { - if !child.complete { - ctx.complete = false - return - } - } - } - }() - - // Resets are registered as the `f` function executes, so nil them here. - // All resets are run in registration order (FIFO). - ctx.resets = []func(){} - defer func() { - for _, r := range ctx.resets { - // panics handled by the previous defer - r() - } - }() - - if f == nil { - // if f is nil, this was either a Convey(..., nil), or a SkipConvey - ctx.reporter.Report(reporting.NewSkipReport()) - } else { - f(ctx) - } -} - -// assertionReport is a helper for So and SkipSo which makes the report and -// then possibly panics, depending on the current context's failureMode. -func (ctx *context) assertionReport(r *reporting.AssertionResult) { - ctx.reporter.Report(r) - if r.Failure != "" && ctx.failureMode == FailureHalts { - panic(failureHalt) - } -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/convey.goconvey b/vendor/github.com/smartystreets/goconvey/convey/convey.goconvey deleted file mode 100644 index a2d9327..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/convey.goconvey +++ /dev/null @@ -1,4 +0,0 @@ -#ignore --timeout=1s -#-covermode=count -#-coverpkg=github.com/smartystreets/goconvey/convey,github.com/smartystreets/goconvey/convey/gotest,github.com/smartystreets/goconvey/convey/reporting \ No newline at end of file diff --git a/vendor/github.com/smartystreets/goconvey/convey/discovery.go b/vendor/github.com/smartystreets/goconvey/convey/discovery.go deleted file mode 100644 index eb8d4cb..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/discovery.go +++ /dev/null @@ -1,103 +0,0 @@ -package convey - -type actionSpecifier uint8 - -const ( - noSpecifier actionSpecifier = iota - skipConvey - focusConvey -) - -type suite struct { - Situation string - Test t - Focus bool - Func func(C) // nil means skipped - FailMode FailureMode -} - -func newSuite(situation string, failureMode FailureMode, f func(C), test t, specifier actionSpecifier) *suite { - ret := &suite{ - Situation: situation, - Test: test, - Func: f, - FailMode: failureMode, - } - switch specifier { - case skipConvey: - ret.Func = nil - case focusConvey: - ret.Focus = true - } - return ret -} - -func discover(items []interface{}) *suite { - name, items := parseName(items) - test, items := parseGoTest(items) - failure, items := parseFailureMode(items) - action, items := parseAction(items) - specifier, items := parseSpecifier(items) - - if len(items) != 0 { - conveyPanic(parseError) - } - - return newSuite(name, failure, action, test, specifier) -} -func item(items []interface{}) interface{} { - if len(items) == 0 { - conveyPanic(parseError) - } - return items[0] -} -func parseName(items []interface{}) (string, []interface{}) { - if name, parsed := item(items).(string); parsed { - return name, items[1:] - } - conveyPanic(parseError) - panic("never get here") -} -func parseGoTest(items []interface{}) (t, []interface{}) { - if test, parsed := item(items).(t); parsed { - return test, items[1:] - } - return nil, items -} -func parseFailureMode(items []interface{}) (FailureMode, []interface{}) { - if mode, parsed := item(items).(FailureMode); parsed { - return mode, items[1:] - } - return FailureInherits, items -} -func parseAction(items []interface{}) (func(C), []interface{}) { - switch x := item(items).(type) { - case nil: - return nil, items[1:] - case func(C): - return x, items[1:] - case func(): - return func(C) { x() }, items[1:] - } - conveyPanic(parseError) - panic("never get here") -} -func parseSpecifier(items []interface{}) (actionSpecifier, []interface{}) { - if len(items) == 0 { - return noSpecifier, items - } - if spec, ok := items[0].(actionSpecifier); ok { - return spec, items[1:] - } - conveyPanic(parseError) - panic("never get here") -} - -// This interface allows us to pass the *testing.T struct -// throughout the internals of this package without ever -// having to import the "testing" package. -type t interface { - Fail() -} - -const parseError = "You must provide a name (string), then a *testing.T (if in outermost scope), an optional FailureMode, and then an action (func())." diff --git a/vendor/github.com/smartystreets/goconvey/convey/doc.go b/vendor/github.com/smartystreets/goconvey/convey/doc.go deleted file mode 100644 index 2562ce4..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/doc.go +++ /dev/null @@ -1,218 +0,0 @@ -// Package convey contains all of the public-facing entry points to this project. -// This means that it should never be required of the user to import any other -// packages from this project as they serve internal purposes. -package convey - -import "github.com/smartystreets/goconvey/convey/reporting" - -////////////////////////////////// suite ////////////////////////////////// - -// C is the Convey context which you can optionally obtain in your action -// by calling Convey like: -// -// Convey(..., func(c C) { -// ... -// }) -// -// See the documentation on Convey for more details. -// -// All methods in this context behave identically to the global functions of the -// same name in this package. -type C interface { - Convey(items ...interface{}) - SkipConvey(items ...interface{}) - FocusConvey(items ...interface{}) - - So(actual interface{}, assert assertion, expected ...interface{}) - SkipSo(stuff ...interface{}) - - Reset(action func()) - - Println(items ...interface{}) (int, error) - Print(items ...interface{}) (int, error) - Printf(format string, items ...interface{}) (int, error) -} - -// Convey is the method intended for use when declaring the scopes of -// a specification. Each scope has a description and a func() which may contain -// other calls to Convey(), Reset() or Should-style assertions. Convey calls can -// be nested as far as you see fit. -// -// IMPORTANT NOTE: The top-level Convey() within a Test method -// must conform to the following signature: -// -// Convey(description string, t *testing.T, action func()) -// -// All other calls should look like this (no need to pass in *testing.T): -// -// Convey(description string, action func()) -// -// Don't worry, goconvey will panic if you get it wrong so you can fix it. -// -// Additionally, you may explicitly obtain access to the Convey context by doing: -// -// Convey(description string, action func(c C)) -// -// You may need to do this if you want to pass the context through to a -// goroutine, or to close over the context in a handler to a library which -// calls your handler in a goroutine (httptest comes to mind). -// -// All Convey()-blocks also accept an optional parameter of FailureMode which sets -// how goconvey should treat failures for So()-assertions in the block and -// nested blocks. See the constants in this file for the available options. -// -// By default it will inherit from its parent block and the top-level blocks -// default to the FailureHalts setting. -// -// This parameter is inserted before the block itself: -// -// Convey(description string, t *testing.T, mode FailureMode, action func()) -// Convey(description string, mode FailureMode, action func()) -// -// See the examples package for, well, examples. -func Convey(items ...interface{}) { - if ctx := getCurrentContext(); ctx == nil { - rootConvey(items...) - } else { - ctx.Convey(items...) - } -} - -// SkipConvey is analagous to Convey except that the scope is not executed -// (which means that child scopes defined within this scope are not run either). -// The reporter will be notified that this step was skipped. -func SkipConvey(items ...interface{}) { - Convey(append(items, skipConvey)...) -} - -// FocusConvey is has the inverse effect of SkipConvey. If the top-level -// Convey is changed to `FocusConvey`, only nested scopes that are defined -// with FocusConvey will be run. The rest will be ignored completely. This -// is handy when debugging a large suite that runs a misbehaving function -// repeatedly as you can disable all but one of that function -// without swaths of `SkipConvey` calls, just a targeted chain of calls -// to FocusConvey. -func FocusConvey(items ...interface{}) { - Convey(append(items, focusConvey)...) -} - -// Reset registers a cleanup function to be run after each Convey() -// in the same scope. See the examples package for a simple use case. -func Reset(action func()) { - mustGetCurrentContext().Reset(action) -} - -/////////////////////////////////// Assertions /////////////////////////////////// - -// assertion is an alias for a function with a signature that the convey.So() -// method can handle. Any future or custom assertions should conform to this -// method signature. The return value should be an empty string if the assertion -// passes and a well-formed failure message if not. -type assertion func(actual interface{}, expected ...interface{}) string - -const assertionSuccess = "" - -// So is the means by which assertions are made against the system under test. -// The majority of exported names in the assertions package begin with the word -// 'Should' and describe how the first argument (actual) should compare with any -// of the final (expected) arguments. How many final arguments are accepted -// depends on the particular assertion that is passed in as the assert argument. -// See the examples package for use cases and the assertions package for -// documentation on specific assertion methods. A failing assertion will -// cause t.Fail() to be invoked--you should never call this method (or other -// failure-inducing methods) in your test code. Leave that to GoConvey. -func So(actual interface{}, assert assertion, expected ...interface{}) { - mustGetCurrentContext().So(actual, assert, expected...) -} - -// SkipSo is analagous to So except that the assertion that would have been passed -// to So is not executed and the reporter is notified that the assertion was skipped. -func SkipSo(stuff ...interface{}) { - mustGetCurrentContext().SkipSo() -} - -// FailureMode is a type which determines how the So() blocks should fail -// if their assertion fails. See constants further down for acceptable values -type FailureMode string - -const ( - - // FailureContinues is a failure mode which prevents failing - // So()-assertions from halting Convey-block execution, instead - // allowing the test to continue past failing So()-assertions. - FailureContinues FailureMode = "continue" - - // FailureHalts is the default setting for a top-level Convey()-block - // and will cause all failing So()-assertions to halt further execution - // in that test-arm and continue on to the next arm. - FailureHalts FailureMode = "halt" - - // FailureInherits is the default setting for failure-mode, it will - // default to the failure-mode of the parent block. You should never - // need to specify this mode in your tests.. - FailureInherits FailureMode = "inherits" -) - -func (f FailureMode) combine(other FailureMode) FailureMode { - if other == FailureInherits { - return f - } - return other -} - -var defaultFailureMode FailureMode = FailureHalts - -// SetDefaultFailureMode allows you to specify the default failure mode -// for all Convey blocks. It is meant to be used in an init function to -// allow the default mode to be changdd across all tests for an entire packgae -// but it can be used anywhere. -func SetDefaultFailureMode(mode FailureMode) { - if mode == FailureContinues || mode == FailureHalts { - defaultFailureMode = mode - } else { - panic("You may only use the constants named 'FailureContinues' and 'FailureHalts' as default failure modes.") - } -} - -//////////////////////////////////// Print functions //////////////////////////////////// - -// Print is analogous to fmt.Print (and it even calls fmt.Print). It ensures that -// output is aligned with the corresponding scopes in the web UI. -func Print(items ...interface{}) (written int, err error) { - return mustGetCurrentContext().Print(items...) -} - -// Print is analogous to fmt.Println (and it even calls fmt.Println). It ensures that -// output is aligned with the corresponding scopes in the web UI. -func Println(items ...interface{}) (written int, err error) { - return mustGetCurrentContext().Println(items...) -} - -// Print is analogous to fmt.Printf (and it even calls fmt.Printf). It ensures that -// output is aligned with the corresponding scopes in the web UI. -func Printf(format string, items ...interface{}) (written int, err error) { - return mustGetCurrentContext().Printf(format, items...) -} - -/////////////////////////////////////////////////////////////////////////////// - -// SuppressConsoleStatistics prevents automatic printing of console statistics. -// Calling PrintConsoleStatistics explicitly will force printing of statistics. -func SuppressConsoleStatistics() { - reporting.SuppressConsoleStatistics() -} - -// ConsoleStatistics may be called at any time to print assertion statistics. -// Generally, the best place to do this would be in a TestMain function, -// after all tests have been run. Something like this: -// -// func TestMain(m *testing.M) { -// convey.SuppressConsoleStatistics() -// result := m.Run() -// convey.PrintConsoleStatistics() -// os.Exit(result) -// } -// -func PrintConsoleStatistics() { - reporting.PrintConsoleStatistics() -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/gotest/utils.go b/vendor/github.com/smartystreets/goconvey/convey/gotest/utils.go deleted file mode 100644 index 3a5c848..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/gotest/utils.go +++ /dev/null @@ -1,28 +0,0 @@ -// Package gotest contains internal functionality. Although this package -// contains one or more exported names it is not intended for public -// consumption. See the examples package for how to use this project. -package gotest - -import ( - "runtime" - "strings" -) - -func ResolveExternalCaller() (file string, line int, name string) { - var caller_id uintptr - callers := runtime.Callers(0, callStack) - - for x := 0; x < callers; x++ { - caller_id, file, line, _ = runtime.Caller(x) - if strings.HasSuffix(file, "_test.go") || strings.HasSuffix(file, "_tests.go") { - name = runtime.FuncForPC(caller_id).Name() - return - } - } - file, line, name = "", -1, "" - return // panic? -} - -const maxStackDepth = 100 // This had better be enough... - -var callStack []uintptr = make([]uintptr, maxStackDepth, maxStackDepth) diff --git a/vendor/github.com/smartystreets/goconvey/convey/init.go b/vendor/github.com/smartystreets/goconvey/convey/init.go deleted file mode 100644 index 732b721..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/init.go +++ /dev/null @@ -1,81 +0,0 @@ -package convey - -import ( - "flag" - "os" - - "github.com/jtolds/gls" - "github.com/smartystreets/assertions" - "github.com/smartystreets/goconvey/convey/reporting" -) - -func init() { - assertions.GoConveyMode(true) - - declareFlags() - - ctxMgr = gls.NewContextManager() -} - -func declareFlags() { - flag.BoolVar(&json, "json", false, "When true, emits results in JSON blocks. Default: 'false'") - flag.BoolVar(&silent, "silent", false, "When true, all output from GoConvey is suppressed.") - flag.BoolVar(&story, "story", false, "When true, emits story output, otherwise emits dot output. When not provided, this flag mirros the value of the '-test.v' flag") - - if noStoryFlagProvided() { - story = verboseEnabled - } - - // FYI: flag.Parse() is called from the testing package. -} - -func noStoryFlagProvided() bool { - return !story && !storyDisabled -} - -func buildReporter() reporting.Reporter { - selectReporter := os.Getenv("GOCONVEY_REPORTER") - - switch { - case testReporter != nil: - return testReporter - case json || selectReporter == "json": - return reporting.BuildJsonReporter() - case silent || selectReporter == "silent": - return reporting.BuildSilentReporter() - case selectReporter == "dot": - // Story is turned on when verbose is set, so we need to check for dot reporter first. - return reporting.BuildDotReporter() - case story || selectReporter == "story": - return reporting.BuildStoryReporter() - default: - return reporting.BuildDotReporter() - } -} - -var ( - ctxMgr *gls.ContextManager - - // only set by internal tests - testReporter reporting.Reporter -) - -var ( - json bool - silent bool - story bool - - verboseEnabled = flagFound("-test.v=true") - storyDisabled = flagFound("-story=false") -) - -// flagFound parses the command line args manually for flags defined in other -// packages. Like the '-v' flag from the "testing" package, for instance. -func flagFound(flagValue string) bool { - for _, arg := range os.Args { - if arg == flagValue { - return true - } - } - return false -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/nilReporter.go b/vendor/github.com/smartystreets/goconvey/convey/nilReporter.go deleted file mode 100644 index 777b2a5..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/nilReporter.go +++ /dev/null @@ -1,15 +0,0 @@ -package convey - -import ( - "github.com/smartystreets/goconvey/convey/reporting" -) - -type nilReporter struct{} - -func (self *nilReporter) BeginStory(story *reporting.StoryReport) {} -func (self *nilReporter) Enter(scope *reporting.ScopeReport) {} -func (self *nilReporter) Report(report *reporting.AssertionResult) {} -func (self *nilReporter) Exit() {} -func (self *nilReporter) EndStory() {} -func (self *nilReporter) Write(p []byte) (int, error) { return len(p), nil } -func newNilReporter() *nilReporter { return &nilReporter{} } diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/console.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/console.go deleted file mode 100644 index 7bf67db..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/console.go +++ /dev/null @@ -1,16 +0,0 @@ -package reporting - -import ( - "fmt" - "io" -) - -type console struct{} - -func (self *console) Write(p []byte) (n int, err error) { - return fmt.Print(string(p)) -} - -func NewConsole() io.Writer { - return new(console) -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/doc.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/doc.go deleted file mode 100644 index a37d001..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package reporting contains internal functionality related -// to console reporting and output. Although this package has -// exported names is not intended for public consumption. See the -// examples package for how to use this project. -package reporting diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/dot.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/dot.go deleted file mode 100644 index 47d57c6..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/dot.go +++ /dev/null @@ -1,40 +0,0 @@ -package reporting - -import "fmt" - -type dot struct{ out *Printer } - -func (self *dot) BeginStory(story *StoryReport) {} - -func (self *dot) Enter(scope *ScopeReport) {} - -func (self *dot) Report(report *AssertionResult) { - if report.Error != nil { - fmt.Print(redColor) - self.out.Insert(dotError) - } else if report.Failure != "" { - fmt.Print(yellowColor) - self.out.Insert(dotFailure) - } else if report.Skipped { - fmt.Print(yellowColor) - self.out.Insert(dotSkip) - } else { - fmt.Print(greenColor) - self.out.Insert(dotSuccess) - } - fmt.Print(resetColor) -} - -func (self *dot) Exit() {} - -func (self *dot) EndStory() {} - -func (self *dot) Write(content []byte) (written int, err error) { - return len(content), nil // no-op -} - -func NewDotReporter(out *Printer) *dot { - self := new(dot) - self.out = out - return self -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/gotest.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/gotest.go deleted file mode 100644 index c396e16..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/gotest.go +++ /dev/null @@ -1,33 +0,0 @@ -package reporting - -type gotestReporter struct{ test T } - -func (self *gotestReporter) BeginStory(story *StoryReport) { - self.test = story.Test -} - -func (self *gotestReporter) Enter(scope *ScopeReport) {} - -func (self *gotestReporter) Report(r *AssertionResult) { - if !passed(r) { - self.test.Fail() - } -} - -func (self *gotestReporter) Exit() {} - -func (self *gotestReporter) EndStory() { - self.test = nil -} - -func (self *gotestReporter) Write(content []byte) (written int, err error) { - return len(content), nil // no-op -} - -func NewGoTestReporter() *gotestReporter { - return new(gotestReporter) -} - -func passed(r *AssertionResult) bool { - return r.Error == nil && r.Failure == "" -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/init.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/init.go deleted file mode 100644 index 430cf73..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/init.go +++ /dev/null @@ -1,97 +0,0 @@ -package reporting - -import ( - "fmt" - "os" - "runtime" - "strings" -) - -func init() { - if !isXterm() { - monochrome() - } - - if runtime.GOOS == "windows" { - success, failure, error_ = dotSuccess, dotFailure, dotError - } -} - -func BuildJsonReporter() Reporter { - out := NewPrinter(NewConsole()) - return NewReporters( - NewGoTestReporter(), - NewJsonReporter(out)) -} -func BuildDotReporter() Reporter { - out := NewPrinter(NewConsole()) - return NewReporters( - NewGoTestReporter(), - NewDotReporter(out), - NewProblemReporter(out), - consoleStatistics) -} -func BuildStoryReporter() Reporter { - out := NewPrinter(NewConsole()) - return NewReporters( - NewGoTestReporter(), - NewStoryReporter(out), - NewProblemReporter(out), - consoleStatistics) -} -func BuildSilentReporter() Reporter { - out := NewPrinter(NewConsole()) - return NewReporters( - NewGoTestReporter(), - NewSilentProblemReporter(out)) -} - -var ( - newline = "\n" - success = "✔" - failure = "✘" - error_ = "🔥" - skip = "⚠" - dotSuccess = "." - dotFailure = "x" - dotError = "E" - dotSkip = "S" - errorTemplate = "* %s \nLine %d: - %v \n%s\n" - failureTemplate = "* %s \nLine %d:\n%s\n" -) - -var ( - greenColor = "\033[32m" - yellowColor = "\033[33m" - redColor = "\033[31m" - resetColor = "\033[0m" -) - -var consoleStatistics = NewStatisticsReporter(NewPrinter(NewConsole())) - -func SuppressConsoleStatistics() { consoleStatistics.Suppress() } -func PrintConsoleStatistics() { consoleStatistics.PrintSummary() } - -// QuiteMode disables all console output symbols. This is only meant to be used -// for tests that are internal to goconvey where the output is distracting or -// otherwise not needed in the test output. -func QuietMode() { - success, failure, error_, skip, dotSuccess, dotFailure, dotError, dotSkip = "", "", "", "", "", "", "", "" -} - -func monochrome() { - greenColor, yellowColor, redColor, resetColor = "", "", "", "" -} - -func isXterm() bool { - env := fmt.Sprintf("%v", os.Environ()) - return strings.Contains(env, " TERM=isXterm") || - strings.Contains(env, " TERM=xterm") -} - -// This interface allows us to pass the *testing.T struct -// throughout the internals of this tool without ever -// having to import the "testing" package. -type T interface { - Fail() -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/json.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/json.go deleted file mode 100644 index f852697..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/json.go +++ /dev/null @@ -1,88 +0,0 @@ -// TODO: under unit test - -package reporting - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" -) - -type JsonReporter struct { - out *Printer - currentKey []string - current *ScopeResult - index map[string]*ScopeResult - scopes []*ScopeResult -} - -func (self *JsonReporter) depth() int { return len(self.currentKey) } - -func (self *JsonReporter) BeginStory(story *StoryReport) {} - -func (self *JsonReporter) Enter(scope *ScopeReport) { - self.currentKey = append(self.currentKey, scope.Title) - ID := strings.Join(self.currentKey, "|") - if _, found := self.index[ID]; !found { - next := newScopeResult(scope.Title, self.depth(), scope.File, scope.Line) - self.scopes = append(self.scopes, next) - self.index[ID] = next - } - self.current = self.index[ID] -} - -func (self *JsonReporter) Report(report *AssertionResult) { - self.current.Assertions = append(self.current.Assertions, report) -} - -func (self *JsonReporter) Exit() { - self.currentKey = self.currentKey[:len(self.currentKey)-1] -} - -func (self *JsonReporter) EndStory() { - self.report() - self.reset() -} -func (self *JsonReporter) report() { - scopes := []string{} - for _, scope := range self.scopes { - serialized, err := json.Marshal(scope) - if err != nil { - self.out.Println(jsonMarshalFailure) - panic(err) - } - var buffer bytes.Buffer - json.Indent(&buffer, serialized, "", " ") - scopes = append(scopes, buffer.String()) - } - self.out.Print(fmt.Sprintf("%s\n%s,\n%s\n", OpenJson, strings.Join(scopes, ","), CloseJson)) -} -func (self *JsonReporter) reset() { - self.scopes = []*ScopeResult{} - self.index = map[string]*ScopeResult{} - self.currentKey = nil -} - -func (self *JsonReporter) Write(content []byte) (written int, err error) { - self.current.Output += string(content) - return len(content), nil -} - -func NewJsonReporter(out *Printer) *JsonReporter { - self := new(JsonReporter) - self.out = out - self.reset() - return self -} - -const OpenJson = ">->->OPEN-JSON->->->" // "⌦" -const CloseJson = "<-<-<-CLOSE-JSON<-<-<" // "⌫" -const jsonMarshalFailure = ` - -GOCONVEY_JSON_MARSHALL_FAILURE: There was an error when attempting to convert test results to JSON. -Please file a bug report and reference the code that caused this failure if possible. - -Here's the panic: - -` diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/printer.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/printer.go deleted file mode 100644 index 6d4a879..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/printer.go +++ /dev/null @@ -1,57 +0,0 @@ -package reporting - -import ( - "fmt" - "io" - "strings" -) - -type Printer struct { - out io.Writer - prefix string -} - -func (self *Printer) Println(message string, values ...interface{}) { - formatted := self.format(message, values...) + newline - self.out.Write([]byte(formatted)) -} - -func (self *Printer) Print(message string, values ...interface{}) { - formatted := self.format(message, values...) - self.out.Write([]byte(formatted)) -} - -func (self *Printer) Insert(text string) { - self.out.Write([]byte(text)) -} - -func (self *Printer) format(message string, values ...interface{}) string { - var formatted string - if len(values) == 0 { - formatted = self.prefix + message - } else { - formatted = self.prefix + fmt.Sprintf(message, values...) - } - indented := strings.Replace(formatted, newline, newline+self.prefix, -1) - return strings.TrimRight(indented, space) -} - -func (self *Printer) Indent() { - self.prefix += pad -} - -func (self *Printer) Dedent() { - if len(self.prefix) >= padLength { - self.prefix = self.prefix[:len(self.prefix)-padLength] - } -} - -func NewPrinter(out io.Writer) *Printer { - self := new(Printer) - self.out = out - return self -} - -const space = " " -const pad = space + space -const padLength = len(pad) diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/problems.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/problems.go deleted file mode 100644 index 9ae493a..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/problems.go +++ /dev/null @@ -1,80 +0,0 @@ -package reporting - -import "fmt" - -type problem struct { - silent bool - out *Printer - errors []*AssertionResult - failures []*AssertionResult -} - -func (self *problem) BeginStory(story *StoryReport) {} - -func (self *problem) Enter(scope *ScopeReport) {} - -func (self *problem) Report(report *AssertionResult) { - if report.Error != nil { - self.errors = append(self.errors, report) - } else if report.Failure != "" { - self.failures = append(self.failures, report) - } -} - -func (self *problem) Exit() {} - -func (self *problem) EndStory() { - self.show(self.showErrors, redColor) - self.show(self.showFailures, yellowColor) - self.prepareForNextStory() -} -func (self *problem) show(display func(), color string) { - if !self.silent { - fmt.Print(color) - } - display() - if !self.silent { - fmt.Print(resetColor) - } - self.out.Dedent() -} -func (self *problem) showErrors() { - for i, e := range self.errors { - if i == 0 { - self.out.Println("\nErrors:\n") - self.out.Indent() - } - self.out.Println(errorTemplate, e.File, e.Line, e.Error, e.StackTrace) - } -} -func (self *problem) showFailures() { - for i, f := range self.failures { - if i == 0 { - self.out.Println("\nFailures:\n") - self.out.Indent() - } - self.out.Println(failureTemplate, f.File, f.Line, f.Failure) - } -} - -func (self *problem) Write(content []byte) (written int, err error) { - return len(content), nil // no-op -} - -func NewProblemReporter(out *Printer) *problem { - self := new(problem) - self.out = out - self.prepareForNextStory() - return self -} - -func NewSilentProblemReporter(out *Printer) *problem { - self := NewProblemReporter(out) - self.silent = true - return self -} - -func (self *problem) prepareForNextStory() { - self.errors = []*AssertionResult{} - self.failures = []*AssertionResult{} -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/reporter.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/reporter.go deleted file mode 100644 index cce6c5e..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/reporter.go +++ /dev/null @@ -1,39 +0,0 @@ -package reporting - -import "io" - -type Reporter interface { - BeginStory(story *StoryReport) - Enter(scope *ScopeReport) - Report(r *AssertionResult) - Exit() - EndStory() - io.Writer -} - -type reporters struct{ collection []Reporter } - -func (self *reporters) BeginStory(s *StoryReport) { self.foreach(func(r Reporter) { r.BeginStory(s) }) } -func (self *reporters) Enter(s *ScopeReport) { self.foreach(func(r Reporter) { r.Enter(s) }) } -func (self *reporters) Report(a *AssertionResult) { self.foreach(func(r Reporter) { r.Report(a) }) } -func (self *reporters) Exit() { self.foreach(func(r Reporter) { r.Exit() }) } -func (self *reporters) EndStory() { self.foreach(func(r Reporter) { r.EndStory() }) } - -func (self *reporters) Write(contents []byte) (written int, err error) { - self.foreach(func(r Reporter) { - written, err = r.Write(contents) - }) - return written, err -} - -func (self *reporters) foreach(action func(Reporter)) { - for _, r := range self.collection { - action(r) - } -} - -func NewReporters(collection ...Reporter) *reporters { - self := new(reporters) - self.collection = collection - return self -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey b/vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey deleted file mode 100644 index 7998285..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey +++ /dev/null @@ -1,2 +0,0 @@ -#ignore --timeout=1s diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/reports.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/reports.go deleted file mode 100644 index 659a0ec..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/reports.go +++ /dev/null @@ -1,177 +0,0 @@ -package reporting - -import ( - "encoding/json" - "fmt" - "runtime" - "strings" - - "github.com/smartystreets/goconvey/convey/gotest" -) - -////////////////// ScopeReport //////////////////// - -type ScopeReport struct { - Title string - File string - Line int -} - -func NewScopeReport(title string) *ScopeReport { - file, line, _ := gotest.ResolveExternalCaller() - self := new(ScopeReport) - self.Title = title - self.File = file - self.Line = line - return self -} - -////////////////// ScopeResult //////////////////// - -type ScopeResult struct { - Title string - File string - Line int - Depth int - Assertions []*AssertionResult - Output string -} - -func newScopeResult(title string, depth int, file string, line int) *ScopeResult { - self := new(ScopeResult) - self.Title = title - self.Depth = depth - self.File = file - self.Line = line - self.Assertions = []*AssertionResult{} - return self -} - -/////////////////// StoryReport ///////////////////// - -type StoryReport struct { - Test T - Name string - File string - Line int -} - -func NewStoryReport(test T) *StoryReport { - file, line, name := gotest.ResolveExternalCaller() - name = removePackagePath(name) - self := new(StoryReport) - self.Test = test - self.Name = name - self.File = file - self.Line = line - return self -} - -// name comes in looking like "github.com/smartystreets/goconvey/examples.TestName". -// We only want the stuff after the last '.', which is the name of the test function. -func removePackagePath(name string) string { - parts := strings.Split(name, ".") - return parts[len(parts)-1] -} - -/////////////////// FailureView //////////////////////// - -type FailureView struct { - Message string - Expected string - Actual string -} - -////////////////////AssertionResult ////////////////////// - -type AssertionResult struct { - File string - Line int - Expected string - Actual string - Failure string - Error interface{} - StackTrace string - Skipped bool -} - -func NewFailureReport(failure string) *AssertionResult { - report := new(AssertionResult) - report.File, report.Line = caller() - report.StackTrace = stackTrace() - parseFailure(failure, report) - return report -} -func parseFailure(failure string, report *AssertionResult) { - view := new(FailureView) - err := json.Unmarshal([]byte(failure), view) - if err == nil { - report.Failure = view.Message - report.Expected = view.Expected - report.Actual = view.Actual - } else { - report.Failure = failure - } -} -func NewErrorReport(err interface{}) *AssertionResult { - report := new(AssertionResult) - report.File, report.Line = caller() - report.StackTrace = fullStackTrace() - report.Error = fmt.Sprintf("%v", err) - return report -} -func NewSuccessReport() *AssertionResult { - return new(AssertionResult) -} -func NewSkipReport() *AssertionResult { - report := new(AssertionResult) - report.File, report.Line = caller() - report.StackTrace = fullStackTrace() - report.Skipped = true - return report -} - -func caller() (file string, line int) { - file, line, _ = gotest.ResolveExternalCaller() - return -} - -func stackTrace() string { - buffer := make([]byte, 1024*64) - n := runtime.Stack(buffer, false) - return removeInternalEntries(string(buffer[:n])) -} -func fullStackTrace() string { - buffer := make([]byte, 1024*64) - n := runtime.Stack(buffer, true) - return removeInternalEntries(string(buffer[:n])) -} -func removeInternalEntries(stack string) string { - lines := strings.Split(stack, newline) - filtered := []string{} - for _, line := range lines { - if !isExternal(line) { - filtered = append(filtered, line) - } - } - return strings.Join(filtered, newline) -} -func isExternal(line string) bool { - for _, p := range internalPackages { - if strings.Contains(line, p) { - return true - } - } - return false -} - -// NOTE: any new packages that host goconvey packages will need to be added here! -// An alternative is to scan the goconvey directory and then exclude stuff like -// the examples package but that's nasty too. -var internalPackages = []string{ - "goconvey/assertions", - "goconvey/convey", - "goconvey/execution", - "goconvey/gotest", - "goconvey/reporting", -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/statistics.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/statistics.go deleted file mode 100644 index 28e1d20..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/statistics.go +++ /dev/null @@ -1,89 +0,0 @@ -package reporting - -import "fmt" - -func (self *statistics) BeginStory(story *StoryReport) {} - -func (self *statistics) Enter(scope *ScopeReport) {} - -func (self *statistics) Report(report *AssertionResult) { - if !self.failing && report.Failure != "" { - self.failing = true - } - if !self.erroring && report.Error != nil { - self.erroring = true - } - if report.Skipped { - self.skipped += 1 - } else { - self.total++ - } -} - -func (self *statistics) Exit() {} - -func (self *statistics) EndStory() { - if !self.suppressed { - self.PrintSummary() - } -} - -func (self *statistics) Suppress() { - self.suppressed = true -} - -func (self *statistics) PrintSummary() { - self.reportAssertions() - self.reportSkippedSections() - self.completeReport() -} -func (self *statistics) reportAssertions() { - self.decideColor() - self.out.Print("\n%d total %s", self.total, plural("assertion", self.total)) -} -func (self *statistics) decideColor() { - if self.failing && !self.erroring { - fmt.Print(yellowColor) - } else if self.erroring { - fmt.Print(redColor) - } else { - fmt.Print(greenColor) - } -} -func (self *statistics) reportSkippedSections() { - if self.skipped > 0 { - fmt.Print(yellowColor) - self.out.Print(" (one or more sections skipped)") - } -} -func (self *statistics) completeReport() { - fmt.Print(resetColor) - self.out.Print("\n") - self.out.Print("\n") -} - -func (self *statistics) Write(content []byte) (written int, err error) { - return len(content), nil // no-op -} - -func NewStatisticsReporter(out *Printer) *statistics { - self := statistics{} - self.out = out - return &self -} - -type statistics struct { - out *Printer - total int - failing bool - erroring bool - skipped int - suppressed bool -} - -func plural(word string, count int) string { - if count == 1 { - return word - } - return word + "s" -} diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/story.go b/vendor/github.com/smartystreets/goconvey/convey/reporting/story.go deleted file mode 100644 index 9e73c97..0000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/story.go +++ /dev/null @@ -1,73 +0,0 @@ -// TODO: in order for this reporter to be completely honest -// we need to retrofit to be more like the json reporter such that: -// 1. it maintains ScopeResult collections, which count assertions -// 2. it reports only after EndStory(), so that all tick marks -// are placed near the appropriate title. -// 3. Under unit test - -package reporting - -import ( - "fmt" - "strings" -) - -type story struct { - out *Printer - titlesById map[string]string - currentKey []string -} - -func (self *story) BeginStory(story *StoryReport) {} - -func (self *story) Enter(scope *ScopeReport) { - self.out.Indent() - - self.currentKey = append(self.currentKey, scope.Title) - ID := strings.Join(self.currentKey, "|") - - if _, found := self.titlesById[ID]; !found { - self.out.Println("") - self.out.Print(scope.Title) - self.out.Insert(" ") - self.titlesById[ID] = scope.Title - } -} - -func (self *story) Report(report *AssertionResult) { - if report.Error != nil { - fmt.Print(redColor) - self.out.Insert(error_) - } else if report.Failure != "" { - fmt.Print(yellowColor) - self.out.Insert(failure) - } else if report.Skipped { - fmt.Print(yellowColor) - self.out.Insert(skip) - } else { - fmt.Print(greenColor) - self.out.Insert(success) - } - fmt.Print(resetColor) -} - -func (self *story) Exit() { - self.out.Dedent() - self.currentKey = self.currentKey[:len(self.currentKey)-1] -} - -func (self *story) EndStory() { - self.titlesById = make(map[string]string) - self.out.Println("\n") -} - -func (self *story) Write(content []byte) (written int, err error) { - return len(content), nil // no-op -} - -func NewStoryReporter(out *Printer) *story { - self := new(story) - self.out = out - self.titlesById = make(map[string]string) - return self -} diff --git a/vendor/github.com/howeyc/fsnotify/LICENSE b/vendor/golang.org/x/debug/LICENSE similarity index 92% rename from vendor/github.com/howeyc/fsnotify/LICENSE rename to vendor/golang.org/x/debug/LICENSE index f21e540..a2dd15f 100644 --- a/vendor/github.com/howeyc/fsnotify/LICENSE +++ b/vendor/golang.org/x/debug/LICENSE @@ -1,5 +1,4 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2012 fsnotify Authors. All rights reserved. +Copyright (c) 2014 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/golang.org/x/debug/dwarf/buf.go b/vendor/golang.org/x/debug/dwarf/buf.go new file mode 100644 index 0000000..73fcc9a --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/buf.go @@ -0,0 +1,203 @@ +// 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. + +// Buffered reading and decoding of DWARF data streams. + +package dwarf + +import ( + "encoding/binary" + "fmt" + "strconv" +) + +// Data buffer being decoded. +type buf struct { + dwarf *Data + order binary.ByteOrder + format dataFormat + name string + off Offset + data []byte + err error +} + +// Data format, other than byte order. This affects the handling of +// certain field formats. +type dataFormat interface { + // DWARF version number. Zero means unknown. + version() int + + // 64-bit DWARF format? + dwarf64() (dwarf64 bool, isKnown bool) + + // Size of an address, in bytes. Zero means unknown. + addrsize() int +} + +// Some parts of DWARF have no data format, e.g., abbrevs. +type unknownFormat struct{} + +func (u unknownFormat) version() int { + return 0 +} + +func (u unknownFormat) dwarf64() (bool, bool) { + return false, false +} + +func (u unknownFormat) addrsize() int { + return 0 +} + +func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf { + return buf{d, d.order, format, name, off, data, nil} +} + +func (b *buf) slice(length int) buf { + n := *b + data := b.data + b.skip(length) // Will validate length. + n.data = data[:length] + return n +} + +func (b *buf) uint8() uint8 { + if len(b.data) < 1 { + b.error("underflow") + return 0 + } + val := b.data[0] + b.data = b.data[1:] + b.off++ + return val +} + +func (b *buf) bytes(n int) []byte { + if len(b.data) < n { + b.error("underflow") + return nil + } + data := b.data[0:n] + b.data = b.data[n:] + b.off += Offset(n) + return data +} + +func (b *buf) skip(n int) { b.bytes(n) } + +// string returns the NUL-terminated (C-like) string at the start of the buffer. +// The terminal NUL is discarded. +func (b *buf) string() string { + for i := 0; i < len(b.data); i++ { + if b.data[i] == 0 { + s := string(b.data[0:i]) + b.data = b.data[i+1:] + b.off += Offset(i + 1) + return s + } + } + b.error("underflow") + return "" +} + +func (b *buf) uint16() uint16 { + a := b.bytes(2) + if a == nil { + return 0 + } + return b.order.Uint16(a) +} + +func (b *buf) uint32() uint32 { + a := b.bytes(4) + if a == nil { + return 0 + } + return b.order.Uint32(a) +} + +func (b *buf) uint64() uint64 { + a := b.bytes(8) + if a == nil { + return 0 + } + return b.order.Uint64(a) +} + +// Read a varint, which is 7 bits per byte, little endian. +// the 0x80 bit means read another byte. +func (b *buf) varint() (c uint64, bits uint) { + for i := 0; i < len(b.data); i++ { + byte := b.data[i] + c |= uint64(byte&0x7F) << bits + bits += 7 + if byte&0x80 == 0 { + b.off += Offset(i + 1) + b.data = b.data[i+1:] + return c, bits + } + } + return 0, 0 +} + +// Unsigned int is just a varint. +func (b *buf) uint() uint64 { + x, _ := b.varint() + return x +} + +// Signed int is a sign-extended varint. +func (b *buf) int() int64 { + ux, bits := b.varint() + x := int64(ux) + if x&(1<<(bits-1)) != 0 { + x |= -1 << bits + } + return x +} + +// Address-sized uint. +func (b *buf) addr() uint64 { + switch b.format.addrsize() { + case 1: + return uint64(b.uint8()) + case 2: + return uint64(b.uint16()) + case 4: + return uint64(b.uint32()) + case 8: + return uint64(b.uint64()) + } + b.error("unknown address size") + return 0 +} + +// assertEmpty checks that everything has been read from b. +func (b *buf) assertEmpty() { + if len(b.data) == 0 { + return + } + if len(b.data) > 5 { + b.error(fmt.Sprintf("unexpected extra data: %x...", b.data[0:5])) + } + b.error(fmt.Sprintf("unexpected extra data: %x", b.data)) +} + +func (b *buf) error(s string) { + if b.err == nil { + b.data = nil + b.err = DecodeError{b.name, b.off, s} + } +} + +type DecodeError struct { + Name string + Offset Offset + Err string +} + +func (e DecodeError) Error() string { + return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err +} diff --git a/vendor/golang.org/x/debug/dwarf/cache.go b/vendor/golang.org/x/debug/dwarf/cache.go new file mode 100644 index 0000000..cf795e7 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/cache.go @@ -0,0 +1,249 @@ +// Copyright 2016 The Go 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 ( + "sort" +) + +// pcToFuncEntries maps PC ranges to function entries. +// +// Each element contains a *Entry for a function and its corresponding start PC. +// If we know the address one past the last instruction of a function, and it is +// not equal to the start address of the next function, we mark that with +// another element containing that address and a nil entry. The elements are +// sorted by PC. Among elements with the same PC, those with non-nil *Entry +// are put earlier. +type pcToFuncEntries []pcToFuncEntry +type pcToFuncEntry struct { + pc uint64 + entry *Entry +} + +func (p pcToFuncEntries) Len() int { return len(p) } +func (p pcToFuncEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p pcToFuncEntries) Less(i, j int) bool { + if p[i].pc != p[j].pc { + return p[i].pc < p[j].pc + } + return p[i].entry != nil && p[j].entry == nil +} + +// nameCache maps each symbol name to a linked list of the entries with that name. +type nameCache map[string]*nameCacheEntry +type nameCacheEntry struct { + entry *Entry + link *nameCacheEntry +} + +// pcToLineEntries maps PCs to line numbers. +// +// It is a slice of (PC, line, file number) triples, sorted by PC. The file +// number is an index into the source files slice. +// If (PC1, line1, file1) and (PC2, line2, file2) are two consecutive elements, +// then the span of addresses [PC1, PC2) belongs to (line1, file1). If an +// element's file number is zero, it only marks the end of a span. +// +// TODO: could save memory by changing pcToLineEntries and lineToPCEntries to use +// interval trees containing references into .debug_line. +type pcToLineEntries []pcToLineEntry +type pcToLineEntry struct { + pc uint64 + line uint64 + file uint64 +} + +func (p pcToLineEntries) Len() int { return len(p) } +func (p pcToLineEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p pcToLineEntries) Less(i, j int) bool { + if p[i].pc != p[j].pc { + return p[i].pc < p[j].pc + } + return p[i].file > p[j].file +} + +// byFileLine is used temporarily while building lineToPCEntries. +type byFileLine []pcToLineEntry + +func (b byFileLine) Len() int { return len(b) } +func (b byFileLine) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byFileLine) Less(i, j int) bool { + if b[i].file != b[j].file { + return b[i].file < b[j].file + } + return b[i].line < b[j].line +} + +// lineToPCEntries maps line numbers to breakpoint addresses. +// +// The slice contains, for each source file in Data, a slice of (line, PC) +// pairs, sorted by line. Note that there may be more than one PC for a line. +type lineToPCEntries [][]lineToPCEntry +type lineToPCEntry struct { + line uint64 + pc uint64 +} + +func (d *Data) buildLineToPCCache(pclfs pcToLineEntries) { + // TODO: only include lines where is_stmt is true + sort.Sort(byFileLine(pclfs)) + // Make a slice of (line, PC) pairs for each (non-zero) file. + var ( + c = make(lineToPCEntries, len(d.sourceFiles)) + curSlice []lineToPCEntry + ) + for i, pclf := range pclfs { + if pclf.file == 0 { + // This entry indicated the end of an instruction sequence, not a breakpoint. + continue + } + curSlice = append(curSlice, lineToPCEntry{line: pclf.line, pc: pclf.pc}) + if i+1 == len(pclfs) || pclf.file != pclfs[i+1].file { + // curSlice now contains all of the entries for pclf.file. + if pclf.file > 0 && pclf.file < uint64(len(c)) { + c[pclf.file] = curSlice + } + curSlice = nil + } + } + d.lineToPCEntries = c +} + +func (d *Data) buildPCToLineCache(cache pcToLineEntries) { + // Sort cache by PC (in increasing order), then by file number (in decreasing order). + sort.Sort(cache) + + // Build a copy without redundant entries. + var out pcToLineEntries + for i, pclf := range cache { + if i > 0 && pclf.pc == cache[i-1].pc { + // This entry is for the same PC as the previous entry. + continue + } + if i > 0 && pclf.file == cache[i-1].file && pclf.line == cache[i-1].line { + // This entry is for the same file and line as the previous entry. + continue + } + out = append(out, pclf) + } + d.pcToLineEntries = out +} + +// buildLineCaches constructs d.sourceFiles, d.lineToPCEntries, d.pcToLineEntries. +func (d *Data) buildLineCaches() { + if len(d.line) == 0 { + return + } + var m lineMachine + // Assume the address_size in the first unit applies to the whole program. + // TODO: we could handle executables containing code for multiple address + // sizes using DW_AT_stmt_list attributes. + if len(d.unit) == 0 { + return + } + buf := makeBuf(d, &d.unit[0], "line", 0, d.line) + if err := m.parseHeader(&buf); err != nil { + return + } + for _, f := range m.header.file { + d.sourceFiles = append(d.sourceFiles, f.name) + } + var cache pcToLineEntries + fn := func(m *lineMachine) bool { + if m.endSequence { + cache = append(cache, pcToLineEntry{ + pc: m.address, + line: 0, + file: 0, + }) + } else { + cache = append(cache, pcToLineEntry{ + pc: m.address, + line: m.line, + file: m.file, + }) + } + return true + } + m.evalCompilationUnit(&buf, fn) + d.buildLineToPCCache(cache) + d.buildPCToLineCache(cache) +} + +// buildInfoCaches initializes nameCache and pcToFuncEntries by walking the +// top-level entries under each compile unit. It swallows any errors in parsing. +func (d *Data) buildInfoCaches() { + // TODO: record errors somewhere? + d.nameCache = make(map[string]*nameCacheEntry) + + var pcToFuncEntries pcToFuncEntries + + r := d.Reader() +loop: + for { + entry, err := r.Next() + if entry == nil || err != nil { + break loop + } + if entry.Tag != TagCompileUnit /* DW_TAG_compile_unit */ { + r.SkipChildren() + continue + } + for { + entry, err := r.Next() + if entry == nil || err != nil { + break loop + } + if entry.Tag == 0 { + // End of children of current compile unit. + break + } + r.SkipChildren() + // Update name-to-entry cache. + if name, ok := entry.Val(AttrName).(string); ok { + d.nameCache[name] = &nameCacheEntry{entry: entry, link: d.nameCache[name]} + } + + // If this entry is a function, update PC-to-containing-function cache. + if entry.Tag != TagSubprogram /* DW_TAG_subprogram */ { + continue + } + + // DW_AT_low_pc, if present, is the address of the first instruction of + // the function. + lowpc, ok := entry.Val(AttrLowpc).(uint64) + if !ok { + continue + } + pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{lowpc, entry}) + + // DW_AT_high_pc, if present (TODO: and of class address) is the address + // one past the last instruction of the function. + highpc, ok := entry.Val(AttrHighpc).(uint64) + if !ok { + continue + } + pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{highpc, nil}) + } + } + // Sort elements by PC. If there are multiple elements with the same PC, + // those with non-nil *Entry are placed earlier. + sort.Sort(pcToFuncEntries) + + // Copy only the first element for each PC to out. + n := 0 + for i, ce := range pcToFuncEntries { + if i == 0 || ce.pc != pcToFuncEntries[i-1].pc { + n++ + } + } + out := make([]pcToFuncEntry, 0, n) + for i, ce := range pcToFuncEntries { + if i == 0 || ce.pc != pcToFuncEntries[i-1].pc { + out = append(out, ce) + } + } + d.pcToFuncEntries = out +} diff --git a/vendor/golang.org/x/debug/dwarf/const.go b/vendor/golang.org/x/debug/dwarf/const.go new file mode 100644 index 0000000..454f789 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/const.go @@ -0,0 +1,467 @@ +// 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. + +// Constants + +package dwarf + +import "strconv" + +// An Attr identifies the attribute type in a DWARF Entry's Field. +type Attr uint32 + +const ( + AttrSibling Attr = 0x01 + AttrLocation Attr = 0x02 + AttrName Attr = 0x03 + AttrOrdering Attr = 0x09 + AttrByteSize Attr = 0x0B + AttrBitOffset Attr = 0x0C + AttrBitSize Attr = 0x0D + AttrStmtList Attr = 0x10 + AttrLowpc Attr = 0x11 + AttrHighpc Attr = 0x12 + AttrLanguage Attr = 0x13 + AttrDiscr Attr = 0x15 + AttrDiscrValue Attr = 0x16 + AttrVisibility Attr = 0x17 + AttrImport Attr = 0x18 + AttrStringLength Attr = 0x19 + AttrCommonRef Attr = 0x1A + AttrCompDir Attr = 0x1B + AttrConstValue Attr = 0x1C + AttrContainingType Attr = 0x1D + AttrDefaultValue Attr = 0x1E + AttrInline Attr = 0x20 + AttrIsOptional Attr = 0x21 + AttrLowerBound Attr = 0x22 + AttrProducer Attr = 0x25 + AttrPrototyped Attr = 0x27 + AttrReturnAddr Attr = 0x2A + AttrStartScope Attr = 0x2C + AttrStrideSize Attr = 0x2E + AttrUpperBound Attr = 0x2F + AttrAbstractOrigin Attr = 0x31 + AttrAccessibility Attr = 0x32 + AttrAddrClass Attr = 0x33 + AttrArtificial Attr = 0x34 + AttrBaseTypes Attr = 0x35 + AttrCalling Attr = 0x36 + AttrCount Attr = 0x37 + AttrDataMemberLoc Attr = 0x38 + AttrDeclColumn Attr = 0x39 + AttrDeclFile Attr = 0x3A + AttrDeclLine Attr = 0x3B + AttrDeclaration Attr = 0x3C + AttrDiscrList Attr = 0x3D + AttrEncoding Attr = 0x3E + AttrExternal Attr = 0x3F + AttrFrameBase Attr = 0x40 + AttrFriend Attr = 0x41 + AttrIdentifierCase Attr = 0x42 + AttrMacroInfo Attr = 0x43 + AttrNamelistItem Attr = 0x44 + AttrPriority Attr = 0x45 + AttrSegment Attr = 0x46 + AttrSpecification Attr = 0x47 + AttrStaticLink Attr = 0x48 + AttrType Attr = 0x49 + AttrUseLocation Attr = 0x4A + AttrVarParam Attr = 0x4B + AttrVirtuality Attr = 0x4C + AttrVtableElemLoc Attr = 0x4D + AttrAllocated Attr = 0x4E + AttrAssociated Attr = 0x4F + AttrDataLocation Attr = 0x50 + AttrStride Attr = 0x51 + AttrEntrypc Attr = 0x52 + AttrUseUTF8 Attr = 0x53 + AttrExtension Attr = 0x54 + AttrRanges Attr = 0x55 + AttrTrampoline Attr = 0x56 + AttrCallColumn Attr = 0x57 + AttrCallFile Attr = 0x58 + AttrCallLine Attr = 0x59 + AttrDescription Attr = 0x5A + + // Go-specific attributes. + AttrGoKind Attr = 0x2900 + AttrGoKey Attr = 0x2901 + AttrGoElem Attr = 0x2902 +) + +var attrNames = [...]string{ + AttrSibling: "Sibling", + AttrLocation: "Location", + AttrName: "Name", + AttrOrdering: "Ordering", + AttrByteSize: "ByteSize", + AttrBitOffset: "BitOffset", + AttrBitSize: "BitSize", + AttrStmtList: "StmtList", + AttrLowpc: "Lowpc", + AttrHighpc: "Highpc", + AttrLanguage: "Language", + AttrDiscr: "Discr", + AttrDiscrValue: "DiscrValue", + AttrVisibility: "Visibility", + AttrImport: "Import", + AttrStringLength: "StringLength", + AttrCommonRef: "CommonRef", + AttrCompDir: "CompDir", + AttrConstValue: "ConstValue", + AttrContainingType: "ContainingType", + AttrDefaultValue: "DefaultValue", + AttrInline: "Inline", + AttrIsOptional: "IsOptional", + AttrLowerBound: "LowerBound", + AttrProducer: "Producer", + AttrPrototyped: "Prototyped", + AttrReturnAddr: "ReturnAddr", + AttrStartScope: "StartScope", + AttrStrideSize: "StrideSize", + AttrUpperBound: "UpperBound", + AttrAbstractOrigin: "AbstractOrigin", + AttrAccessibility: "Accessibility", + AttrAddrClass: "AddrClass", + AttrArtificial: "Artificial", + AttrBaseTypes: "BaseTypes", + AttrCalling: "Calling", + AttrCount: "Count", + AttrDataMemberLoc: "DataMemberLoc", + AttrDeclColumn: "DeclColumn", + AttrDeclFile: "DeclFile", + AttrDeclLine: "DeclLine", + AttrDeclaration: "Declaration", + AttrDiscrList: "DiscrList", + AttrEncoding: "Encoding", + AttrExternal: "External", + AttrFrameBase: "FrameBase", + AttrFriend: "Friend", + AttrIdentifierCase: "IdentifierCase", + AttrMacroInfo: "MacroInfo", + AttrNamelistItem: "NamelistItem", + AttrPriority: "Priority", + AttrSegment: "Segment", + AttrSpecification: "Specification", + AttrStaticLink: "StaticLink", + AttrType: "Type", + AttrUseLocation: "UseLocation", + AttrVarParam: "VarParam", + AttrVirtuality: "Virtuality", + AttrVtableElemLoc: "VtableElemLoc", + AttrAllocated: "Allocated", + AttrAssociated: "Associated", + AttrDataLocation: "DataLocation", + AttrStride: "Stride", + AttrEntrypc: "Entrypc", + AttrUseUTF8: "UseUTF8", + AttrExtension: "Extension", + AttrRanges: "Ranges", + AttrTrampoline: "Trampoline", + AttrCallColumn: "CallColumn", + AttrCallFile: "CallFile", + AttrCallLine: "CallLine", + AttrDescription: "Description", +} + +func (a Attr) String() string { + if int(a) < len(attrNames) { + s := attrNames[a] + if s != "" { + return s + } + } + switch a { + case AttrGoKind: + return "GoKind" + case AttrGoKey: + return "GoKey" + case AttrGoElem: + return "GoElem" + } + return strconv.Itoa(int(a)) +} + +func (a Attr) GoString() string { + if int(a) < len(attrNames) { + s := attrNames[a] + if s != "" { + return "dwarf.Attr" + s + } + } + return "dwarf.Attr(" + strconv.FormatInt(int64(a), 10) + ")" +} + +// A format is a DWARF data encoding format. +type format uint32 + +const ( + // value formats + formAddr format = 0x01 + formDwarfBlock2 format = 0x03 + formDwarfBlock4 format = 0x04 + formData2 format = 0x05 + formData4 format = 0x06 + formData8 format = 0x07 + formString format = 0x08 + formDwarfBlock format = 0x09 + formDwarfBlock1 format = 0x0A + formData1 format = 0x0B + formFlag format = 0x0C + formSdata format = 0x0D + formStrp format = 0x0E + formUdata format = 0x0F + formRefAddr format = 0x10 + formRef1 format = 0x11 + formRef2 format = 0x12 + formRef4 format = 0x13 + 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. +type Tag uint32 + +const ( + TagArrayType Tag = 0x01 + TagClassType Tag = 0x02 + TagEntryPoint Tag = 0x03 + TagEnumerationType Tag = 0x04 + TagFormalParameter Tag = 0x05 + TagImportedDeclaration Tag = 0x08 + TagLabel Tag = 0x0A + TagLexDwarfBlock Tag = 0x0B + TagMember Tag = 0x0D + TagPointerType Tag = 0x0F + TagReferenceType Tag = 0x10 + TagCompileUnit Tag = 0x11 + TagStringType Tag = 0x12 + TagStructType Tag = 0x13 + TagSubroutineType Tag = 0x15 + TagTypedef Tag = 0x16 + TagUnionType Tag = 0x17 + TagUnspecifiedParameters Tag = 0x18 + TagVariant Tag = 0x19 + TagCommonDwarfBlock Tag = 0x1A + TagCommonInclusion Tag = 0x1B + TagInheritance Tag = 0x1C + TagInlinedSubroutine Tag = 0x1D + TagModule Tag = 0x1E + TagPtrToMemberType Tag = 0x1F + TagSetType Tag = 0x20 + TagSubrangeType Tag = 0x21 + TagWithStmt Tag = 0x22 + TagAccessDeclaration Tag = 0x23 + TagBaseType Tag = 0x24 + TagCatchDwarfBlock Tag = 0x25 + TagConstType Tag = 0x26 + TagConstant Tag = 0x27 + TagEnumerator Tag = 0x28 + TagFileType Tag = 0x29 + TagFriend Tag = 0x2A + TagNamelist Tag = 0x2B + TagNamelistItem Tag = 0x2C + TagPackedType Tag = 0x2D + TagSubprogram Tag = 0x2E + TagTemplateTypeParameter Tag = 0x2F + TagTemplateValueParameter Tag = 0x30 + TagThrownType Tag = 0x31 + TagTryDwarfBlock Tag = 0x32 + TagVariantPart Tag = 0x33 + TagVariable Tag = 0x34 + TagVolatileType Tag = 0x35 + // 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{ + TagArrayType: "ArrayType", + TagClassType: "ClassType", + TagEntryPoint: "EntryPoint", + TagEnumerationType: "EnumerationType", + TagFormalParameter: "FormalParameter", + TagImportedDeclaration: "ImportedDeclaration", + TagLabel: "Label", + TagLexDwarfBlock: "LexDwarfBlock", + TagMember: "Member", + TagPointerType: "PointerType", + TagReferenceType: "ReferenceType", + TagCompileUnit: "CompileUnit", + TagStringType: "StringType", + TagStructType: "StructType", + TagSubroutineType: "SubroutineType", + TagTypedef: "Typedef", + TagUnionType: "UnionType", + TagUnspecifiedParameters: "UnspecifiedParameters", + TagVariant: "Variant", + TagCommonDwarfBlock: "CommonDwarfBlock", + TagCommonInclusion: "CommonInclusion", + TagInheritance: "Inheritance", + TagInlinedSubroutine: "InlinedSubroutine", + TagModule: "Module", + TagPtrToMemberType: "PtrToMemberType", + TagSetType: "SetType", + TagSubrangeType: "SubrangeType", + TagWithStmt: "WithStmt", + TagAccessDeclaration: "AccessDeclaration", + TagBaseType: "BaseType", + TagCatchDwarfBlock: "CatchDwarfBlock", + TagConstType: "ConstType", + TagConstant: "Constant", + TagEnumerator: "Enumerator", + TagFileType: "FileType", + TagFriend: "Friend", + TagNamelist: "Namelist", + TagNamelistItem: "NamelistItem", + TagPackedType: "PackedType", + TagSubprogram: "Subprogram", + TagTemplateTypeParameter: "TemplateTypeParameter", + TagTemplateValueParameter: "TemplateValueParameter", + TagThrownType: "ThrownType", + TagTryDwarfBlock: "TryDwarfBlock", + TagVariantPart: "VariantPart", + TagVariable: "Variable", + TagVolatileType: "VolatileType", + TagDwarfProcedure: "DwarfProcedure", + TagRestrictType: "RestrictType", + TagInterfaceType: "InterfaceType", + TagNamespace: "Namespace", + TagImportedModule: "ImportedModule", + TagUnspecifiedType: "UnspecifiedType", + TagPartialUnit: "PartialUnit", + TagImportedUnit: "ImportedUnit", + TagMutableType: "MutableType", + TagCondition: "Condition", + TagSharedType: "SharedType", + TagTypeUnit: "TypeUnit", + TagRvalueReferenceType: "RvalueReferenceType", + TagTemplateAlias: "TemplateAlias", +} + +func (t Tag) String() string { + if int(t) < len(tagNames) { + s := tagNames[t] + if s != "" { + return s + } + } + return strconv.Itoa(int(t)) +} + +func (t Tag) GoString() string { + if int(t) < len(tagNames) { + s := tagNames[t] + if s != "" { + return "dwarf.Tag" + s + } + } + return "dwarf.Tag(" + strconv.FormatInt(int64(t), 10) + ")" +} + +// Location expression operators. +// The debug info encodes value locations like 8(R3) +// as a sequence of these op codes. +// This package does not implement full expressions; +// the opPlusUconst operator is expected by the type parser. +const ( + opAddr = 0x03 /* 1 op, const addr */ + opDeref = 0x06 + opConst1u = 0x08 /* 1 op, 1 byte const */ + opConst1s = 0x09 /* " signed */ + opConst2u = 0x0A /* 1 op, 2 byte const */ + opConst2s = 0x0B /* " signed */ + opConst4u = 0x0C /* 1 op, 4 byte const */ + opConst4s = 0x0D /* " signed */ + opConst8u = 0x0E /* 1 op, 8 byte const */ + opConst8s = 0x0F /* " signed */ + opConstu = 0x10 /* 1 op, LEB128 const */ + opConsts = 0x11 /* " signed */ + opDup = 0x12 + opDrop = 0x13 + opOver = 0x14 + opPick = 0x15 /* 1 op, 1 byte stack index */ + opSwap = 0x16 + opRot = 0x17 + opXderef = 0x18 + opAbs = 0x19 + opAnd = 0x1A + opDiv = 0x1B + opMinus = 0x1C + opMod = 0x1D + opMul = 0x1E + opNeg = 0x1F + opNot = 0x20 + opOr = 0x21 + opPlus = 0x22 + opPlusUconst = 0x23 /* 1 op, ULEB128 addend */ + opShl = 0x24 + opShr = 0x25 + opShra = 0x26 + opXor = 0x27 + opSkip = 0x2F /* 1 op, signed 2-byte constant */ + opBra = 0x28 /* 1 op, signed 2-byte constant */ + opEq = 0x29 + opGe = 0x2A + opGt = 0x2B + opLe = 0x2C + opLt = 0x2D + opNe = 0x2E + opLit0 = 0x30 + /* OpLitN = OpLit0 + N for N = 0..31 */ + opReg0 = 0x50 + /* OpRegN = OpReg0 + N for N = 0..31 */ + opBreg0 = 0x70 /* 1 op, signed LEB128 constant */ + /* OpBregN = OpBreg0 + N for N = 0..31 */ + opRegx = 0x90 /* 1 op, ULEB128 register */ + opFbreg = 0x91 /* 1 op, SLEB128 offset */ + opBregx = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */ + opPiece = 0x93 /* 1 op, ULEB128 size of piece */ + opDerefSize = 0x94 /* 1-byte size of data retrieved */ + opXderefSize = 0x95 /* 1-byte size of data retrieved */ + opNop = 0x96 + /* next four new in Dwarf v3 */ + opPushObjAddr = 0x97 + opCall2 = 0x98 /* 2-byte offset of DIE */ + opCall4 = 0x99 /* 4-byte offset of DIE */ + opCallRef = 0x9A /* 4- or 8- byte offset of DIE */ + /* 0xE0-0xFF reserved for user-specific */ +) + +// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry. +const ( + encAddress = 0x01 + encBoolean = 0x02 + encComplexFloat = 0x03 + encFloat = 0x04 + encSigned = 0x05 + encSignedChar = 0x06 + encUnsigned = 0x07 + encUnsignedChar = 0x08 + encImaginaryFloat = 0x09 +) diff --git a/vendor/golang.org/x/debug/dwarf/entry.go b/vendor/golang.org/x/debug/dwarf/entry.go new file mode 100644 index 0000000..4076ec1 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/entry.go @@ -0,0 +1,407 @@ +// 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. + +// DWARF debug information entry parser. +// An entry is a sequence of data items of a given format. +// The first word in the entry is an index into what DWARF +// calls the ``abbreviation table.'' An abbreviation is really +// just a type descriptor: it's an array of attribute tag/value format pairs. + +package dwarf + +import ( + "errors" + "strconv" +) + +// a single entry's description: a sequence of attributes +type abbrev struct { + tag Tag + children bool + field []afield +} + +type afield struct { + attr Attr + fmt format +} + +// a map from entry format ids to their descriptions +type abbrevTable map[uint32]abbrev + +// ParseAbbrev returns the abbreviation table that starts at byte off +// in the .debug_abbrev section. +func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { + if m, ok := d.abbrevCache[off]; ok { + return m, nil + } + + data := d.abbrev + if off > uint32(len(data)) { + data = nil + } else { + data = data[off:] + } + b := makeBuf(d, unknownFormat{}, "abbrev", 0, data) + + // Error handling is simplified by the buf getters + // returning an endless stream of 0s after an error. + m := make(abbrevTable) + for { + // Table ends with id == 0. + id := uint32(b.uint()) + if id == 0 { + break + } + + // Walk over attributes, counting. + n := 0 + b1 := b // Read from copy of b. + b1.uint() + b1.uint8() + for { + tag := b1.uint() + fmt := b1.uint() + if tag == 0 && fmt == 0 { + break + } + n++ + } + if b1.err != nil { + return nil, b1.err + } + + // Walk over attributes again, this time writing them down. + var a abbrev + a.tag = Tag(b.uint()) + a.children = b.uint8() != 0 + a.field = make([]afield, n) + for i := range a.field { + a.field[i].attr = Attr(b.uint()) + a.field[i].fmt = format(b.uint()) + } + b.uint() + b.uint() + + m[id] = a + } + if b.err != nil { + return nil, b.err + } + d.abbrevCache[off] = m + return m, nil +} + +// An entry is a sequence of attribute/value pairs. +type Entry struct { + Offset Offset // offset of Entry in DWARF info + Tag Tag // tag (kind of Entry) + Children bool // whether Entry is followed by children + Field []Field +} + +// A Field is a single attribute/value pair in an Entry. +type Field struct { + Attr Attr + Val interface{} +} + +// Val returns the value associated with attribute Attr in Entry, +// or nil if there is no such attribute. +// +// A common idiom is to merge the check for nil return with +// the check that the value has the expected dynamic type, as in: +// v, ok := e.Val(AttrSibling).(int64); +// +func (e *Entry) Val(a Attr) interface{} { + for _, f := range e.Field { + if f.Attr == a { + return f.Val + } + } + return nil +} + +// An Offset represents the location of an Entry within the DWARF info. +// (See Reader.Seek.) +type Offset uint32 + +// Entry reads a single entry from buf, decoding +// according to the given abbreviation table. +func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { + off := b.off + id := uint32(b.uint()) + if id == 0 { + return &Entry{} + } + a, ok := atab[id] + if !ok { + b.error("unknown abbreviation table index") + return nil + } + e := &Entry{ + Offset: off, + Tag: a.tag, + Children: a.children, + Field: make([]Field, len(a.field)), + } + for i := range e.Field { + e.Field[i].Attr = a.field[i].attr + fmt := a.field[i].fmt + if fmt == formIndirect { + fmt = format(b.uint()) + } + var val interface{} + switch fmt { + default: + b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16)) + + // address + case formAddr: + val = b.addr() + + // block + case formDwarfBlock1: + val = b.bytes(int(b.uint8())) + case formDwarfBlock2: + val = b.bytes(int(b.uint16())) + case formDwarfBlock4: + val = b.bytes(int(b.uint32())) + case formDwarfBlock: + val = b.bytes(int(b.uint())) + + // constant + case formData1: + val = int64(b.uint8()) + case formData2: + val = int64(b.uint16()) + case formData4: + val = int64(b.uint32()) + case formData8: + val = int64(b.uint64()) + case formSdata: + val = int64(b.int()) + case formUdata: + val = int64(b.uint()) + + // flag + case formFlag: + val = b.uint8() == 1 + // New in DWARF 4. + case formFlagPresent: + // The attribute is implicitly indicated as present, and no value is + // encoded in the debugging information entry itself. + val = true + + // reference to other entry + case formRefAddr: + vers := b.format.version() + if vers == 0 { + b.error("unknown version for DW_FORM_ref_addr") + } else if vers == 2 { + val = Offset(b.addr()) + } else { + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for DW_FORM_ref_addr") + } else if is64 { + val = Offset(b.uint64()) + } else { + val = Offset(b.uint32()) + } + } + case formRef1: + val = Offset(b.uint8()) + ubase + case formRef2: + val = Offset(b.uint16()) + ubase + case formRef4: + val = Offset(b.uint32()) + ubase + case formRef8: + val = Offset(b.uint64()) + ubase + case formRefUdata: + val = Offset(b.uint()) + ubase + + // string + case formString: + val = b.string() + case formStrp: + off := b.uint32() // offset into .debug_str + if b.err != nil { + return nil + } + b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str) + b1.skip(int(off)) + val = b1.string() + if b1.err != nil { + b.err = b1.err + return nil + } + + // lineptr, loclistptr, macptr, rangelistptr + // New in DWARF 4, but clang can generate them with -gdwarf-2. + // Section reference, replacing use of formData4 and formData8. + case formSecOffset, formGnuRefAlt, formGnuStrpAlt: + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16)) + } else if is64 { + val = int64(b.uint64()) + } else { + val = int64(b.uint32()) + } + + // exprloc + // New in DWARF 4. + case formExprloc: + val = b.bytes(int(b.uint())) + + // reference + // New in DWARF 4. + case formRefSig8: + // 64-bit type signature. + val = b.uint64() + } + e.Field[i].Val = val + } + if b.err != nil { + return nil + } + return e +} + +// A Reader allows reading Entry structures from a DWARF ``info'' section. +// The Entry structures are arranged in a tree. The Reader's Next function +// return successive entries from a pre-order traversal of the tree. +// If an entry has children, its Children field will be true, and the children +// follow, terminated by an Entry with Tag 0. +type Reader struct { + b buf + d *Data + err error + unit int + lastChildren bool // .Children of last entry returned by Next + lastSibling Offset // .Val(AttrSibling) of last entry returned by Next +} + +// Reader returns a new Reader for Data. +// The reader is positioned at byte offset 0 in the DWARF ``info'' section. +func (d *Data) Reader() *Reader { + r := &Reader{d: d} + r.Seek(0) + return r +} + +// AddressSize returns the size in bytes of addresses in the current compilation +// unit. +func (r *Reader) AddressSize() int { + return r.d.unit[r.unit].asize +} + +// Seek positions the Reader at offset off in the encoded entry stream. +// Offset 0 can be used to denote the first entry. +func (r *Reader) Seek(off Offset) { + d := r.d + r.err = nil + r.lastChildren = false + if off == 0 { + if len(d.unit) == 0 { + return + } + u := &d.unit[0] + r.unit = 0 + r.b = makeBuf(r.d, u, "info", u.off, u.data) + return + } + + // TODO(rsc): binary search (maybe a new package) + var i int + var u *unit + for i = range d.unit { + u = &d.unit[i] + if u.off <= off && off < u.off+Offset(len(u.data)) { + r.unit = i + r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) + return + } + } + r.err = errors.New("offset out of range") +} + +// maybeNextUnit advances to the next unit if this one is finished. +func (r *Reader) maybeNextUnit() { + for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { + r.unit++ + u := &r.d.unit[r.unit] + r.b = makeBuf(r.d, u, "info", u.off, u.data) + } +} + +// Next reads the next entry from the encoded entry stream. +// It returns nil, nil when it reaches the end of the section. +// It returns an error if the current offset is invalid or the data at the +// offset cannot be decoded as a valid Entry. +func (r *Reader) Next() (*Entry, error) { + if r.err != nil { + return nil, r.err + } + r.maybeNextUnit() + if len(r.b.data) == 0 { + return nil, nil + } + u := &r.d.unit[r.unit] + e := r.b.entry(u.atable, u.base) + if r.b.err != nil { + r.err = r.b.err + return nil, r.err + } + if e != nil { + r.lastChildren = e.Children + if r.lastChildren { + r.lastSibling, _ = e.Val(AttrSibling).(Offset) + } + } else { + r.lastChildren = false + } + return e, nil +} + +// SkipChildren skips over the child entries associated with +// the last Entry returned by Next. If that Entry did not have +// children or Next has not been called, SkipChildren is a no-op. +func (r *Reader) SkipChildren() { + if r.err != nil || !r.lastChildren { + return + } + + // If the last entry had a sibling attribute, + // that attribute gives the offset of the next + // sibling, so we can avoid decoding the + // child subtrees. + if r.lastSibling >= r.b.off { + r.Seek(r.lastSibling) + return + } + + for { + e, err := r.Next() + if err != nil || e == nil || e.Tag == 0 { + break + } + if e.Children { + r.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/vendor/golang.org/x/debug/dwarf/frame.go b/vendor/golang.org/x/debug/dwarf/frame.go new file mode 100644 index 0000000..c112c02 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/frame.go @@ -0,0 +1,299 @@ +// 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. + +// Mapping from PC to SP offset (called CFA - Canonical Frame Address - in DWARF). +// This value is the offset from the stack pointer to the virtual frame pointer +// (address of zeroth argument) at each PC value in the program. + +package dwarf + +import "fmt" + +// http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.4 page 126 +// We implement only the CFA column of the table, not the location +// information about other registers. In other words, we implement +// only what we need to understand Go programs compiled by gc. + +// PCToSPOffset returns the offset, at the specified PC, to add to the +// SP to reach the virtual frame pointer, which corresponds to the +// address of the zeroth argument of the function, the word on the +// stack immediately above the return PC. +func (d *Data) PCToSPOffset(pc uint64) (offset int64, err error) { + if len(d.frame) == 0 { + return 0, fmt.Errorf("PCToSPOffset: no frame table") + } + var m frameMachine + // Assume the first info unit is the same as us. Extremely likely. TODO? + if len(d.unit) == 0 { + return 0, fmt.Errorf("PCToSPOffset: no info section") + } + buf := makeBuf(d, &d.unit[0], "frame", 0, d.frame) + for len(buf.data) > 0 { + offset, err := m.evalCompilationUnit(&buf, pc) + if err != nil { + return 0, err + } + return offset, nil + } + return 0, fmt.Errorf("PCToSPOffset: no frame defined for PC %#x", pc) +} + +// Call Frame instructions. Figure 40, page 181. +// Structure is high two bits plus low 6 bits specified by + in comment. +// Some take one or two operands. +const ( + frameNop = 0<<6 + 0x00 + frameAdvanceLoc = 1<<6 + 0x00 // + delta + frameOffset = 2<<6 + 0x00 // + register op: ULEB128 offset + frameRestore = 3<<6 + 0x00 // + register + frameSetLoc = 0<<6 + 0x01 // op: address + frameAdvanceLoc1 = 0<<6 + 0x02 // op: 1-byte delta + frameAdvanceLoc2 = 0<<6 + 0x03 // op: 2-byte delta + frameAdvanceLoc4 = 0<<6 + 0x04 // op: 4-byte delta + frameOffsetExtended = 0<<6 + 0x05 // ops: ULEB128 register ULEB128 offset + frameRestoreExtended = 0<<6 + 0x06 // op: ULEB128 register + frameUndefined = 0<<6 + 0x07 // op: ULEB128 register + frameSameValue = 0<<6 + 0x08 // op: ULEB128 register + frameRegister = 0<<6 + 0x09 // op: ULEB128 register ULEB128 register + frameRememberState = 0<<6 + 0x0a + frameRestoreState = 0<<6 + 0x0b + frameDefCFA = 0<<6 + 0x0c // op: ULEB128 register ULEB128 offset + frameDefCFARegister = 0<<6 + 0x0d // op: ULEB128 register + frameDefCFAOffset = 0<<6 + 0x0e // op: ULEB128 offset + frameDefCFAExpression = 0<<6 + 0x0f // op: BLOCK + frameExpression = 0<<6 + 0x10 // op: ULEB128 register BLOCK + frameOffsetExtendedSf = 0<<6 + 0x11 // op: ULEB128 register SLEB128 offset + frameDefCFASf = 0<<6 + 0x12 // op: ULEB128 register SLEB128 offset + frameDefCFAOffsetSf = 0<<6 + 0x13 // op: SLEB128 offset + frameValOffset = 0<<6 + 0x14 // op: ULEB128 ULEB128 + frameValOffsetSf = 0<<6 + 0x15 // op: ULEB128 SLEB128 + frameValExpression = 0<<6 + 0x16 // op: ULEB128 BLOCK + frameLoUser = 0<<6 + 0x1c + frameHiUser = 0<<6 + 0x3f +) + +// frameMachine represents the PC/SP engine. +// Section 6.4, page 129. +type frameMachine struct { + // Initial values from CIE. + version uint8 // Version number, "independent of DWARF version" + augmentation string // Augmentation; treated as unexpected for now. TODO. + addressSize uint8 // In DWARF v4 and above. Size of a target address. + segmentSize uint8 // In DWARF v4 and above. Size of a segment selector. + codeAlignmentFactor uint64 // Unit of code size in advance instructions. + dataAlignmentFactor int64 // Unit of data size in certain offset instructions. + returnAddressRegister int // Pseudo-register (actually data column) representing return address. + returnRegisterOffset int64 // Offset to saved PC from CFA in bytes. + // CFA definition. + cfaRegister int // Which register represents the SP. + cfaOffset int64 // CFA offset value. + // Running machine. + location uint64 +} + +// evalCompilationUnit scans the frame data for one compilation unit to retrieve +// the offset information for the specified pc. +func (m *frameMachine) evalCompilationUnit(b *buf, pc uint64) (int64, error) { + err := m.parseCIE(b) + if err != nil { + return 0, err + } + for { + offset, found, err := m.scanFDE(b, pc) + if err != nil { + return 0, err + } + if found { + return offset, nil + } + } +} + +// parseCIE assumes the incoming buffer starts with a CIE block and parses it +// to initialize a frameMachine. +func (m *frameMachine) parseCIE(allBuf *buf) error { + length := int(allBuf.uint32()) + if len(allBuf.data) < length { + return fmt.Errorf("CIE parse error: too short") + } + // Create buffer for just this section. + b := allBuf.slice(length) + cie := b.uint32() + if cie != 0xFFFFFFFF { + return fmt.Errorf("CIE parse error: not CIE: %x", cie) + } + m.version = b.uint8() + if m.version != 3 && m.version != 4 { + return fmt.Errorf("CIE parse error: unsupported version %d", m.version) + } + m.augmentation = b.string() + if len(m.augmentation) > 0 { + return fmt.Errorf("CIE: can't handled augmentation string %q", m.augmentation) + } + if m.version >= 4 { + m.addressSize = b.uint8() + m.segmentSize = b.uint8() + } else { + // Unused. Gc generates version 3, so these values will not be + // set, but they are also not used so it's OK. + } + m.codeAlignmentFactor = b.uint() + m.dataAlignmentFactor = b.int() + m.returnAddressRegister = int(b.uint()) + + // Initial instructions. At least for Go, establishes SP register number + // and initial value of CFA offset at start of function. + _, err := m.run(&b, ^uint64(0)) + if err != nil { + return err + } + + // There's padding, but we can ignore it. + return nil +} + +// scanFDE assumes the incoming buffer starts with a FDE block and parses it +// to run a frameMachine and, if the PC is represented in its range, return +// the CFA offset for that PC. The boolean returned reports whether the +// PC is in range for this FDE. +func (m *frameMachine) scanFDE(allBuf *buf, pc uint64) (int64, bool, error) { + length := int(allBuf.uint32()) + if len(allBuf.data) < length { + return 0, false, fmt.Errorf("FDE parse error: too short") + } + if length <= 0 { + if length == 0 { + // EOF. + return 0, false, fmt.Errorf("PC %#x not found in PC/SP table", pc) + } + return 0, false, fmt.Errorf("bad FDE length %d", length) + } + // Create buffer for just this section. + b := allBuf.slice(length) + cieOffset := b.uint32() // TODO assumes 32 bits. + // Expect 0: first CIE in this segment. TODO. + if cieOffset != 0 { + return 0, false, fmt.Errorf("FDE parse error: bad CIE offset: %.2x", cieOffset) + } + // Initial location. + m.location = b.addr() + addressRange := b.addr() + // If the PC is not in this function, there's no point in executing the instructions. + if pc < m.location || m.location+addressRange <= pc { + return 0, false, nil + } + // The PC appears in this FDE. Scan to find the location. + offset, err := m.run(&b, pc) + if err != nil { + return 0, false, err + } + + // There's padding, but we can ignore it. + return offset, true, nil +} + +// run executes the instructions in the buffer, which has been sliced to contain +// only the data for this block. When we run out of data, we return. +// Since we are only called when we know the PC is in this block, reaching +// EOF is not an error, it just means the final CFA definition matches the +// tail of the block that holds the PC. +// The return value is the CFA at the end of the block or the PC, whichever +// comes first. +func (m *frameMachine) run(b *buf, pc uint64) (int64, error) { + // We run the machine at location == PC because if the PC is at the first + // instruction of a block, the definition of its offset arrives as an + // offset-defining operand after the PC is set to that location. + for m.location <= pc && len(b.data) > 0 { + op := b.uint8() + // Ops with embedded operands + switch op & 0xC0 { + case frameAdvanceLoc: // (6.4.2.1) + // delta in low bits + m.location += uint64(op & 0x3F) + continue + case frameOffset: // (6.4.2.3) + // Register in low bits; ULEB128 offset. + // For Go binaries we only see this in the CIE for the return address register. + if int(op&0x3F) != m.returnAddressRegister { + return 0, fmt.Errorf("invalid frameOffset register R%d should be R%d", op&0x3f, m.returnAddressRegister) + } + m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor + continue + case frameRestore: // (6.4.2.3) + // register in low bits + return 0, fmt.Errorf("unimplemented frameRestore(R%d)\n", op&0x3F) + } + + // The remaining ops do not have embedded operands. + + switch op { + // Row creation instructions (6.4.2.1) + case frameNop: + case frameSetLoc: // op: address + return 0, fmt.Errorf("unimplemented setloc") // what size is operand? + case frameAdvanceLoc1: // op: 1-byte delta + m.location += uint64(b.uint8()) + case frameAdvanceLoc2: // op: 2-byte delta + m.location += uint64(b.uint16()) + case frameAdvanceLoc4: // op: 4-byte delta + m.location += uint64(b.uint32()) + + // CFA definition instructions (6.4.2.2) + case frameDefCFA: // op: ULEB128 register ULEB128 offset + m.cfaRegister = int(b.int()) + m.cfaOffset = int64(b.uint()) + case frameDefCFASf: // op: ULEB128 register SLEB128 offset + return 0, fmt.Errorf("unimplemented frameDefCFASf") + case frameDefCFARegister: // op: ULEB128 register + return 0, fmt.Errorf("unimplemented frameDefCFARegister") + case frameDefCFAOffset: // op: ULEB128 offset + return 0, fmt.Errorf("unimplemented frameDefCFAOffset") + case frameDefCFAOffsetSf: // op: SLEB128 offset + offset := b.int() + m.cfaOffset = offset * m.dataAlignmentFactor + // TODO: Verify we are using a factored offset. + case frameDefCFAExpression: // op: BLOCK + return 0, fmt.Errorf("unimplemented frameDefCFAExpression") + + // Register Rule instructions (6.4.2.3) + case frameOffsetExtended: // ops: ULEB128 register ULEB128 offset + // The same as frameOffset, but with the register specified in an operand. + reg := b.uint() + // For Go binaries we only see this in the CIE for the return address register. + if reg != uint64(m.returnAddressRegister) { + return 0, fmt.Errorf("invalid frameOffsetExtended: register R%d should be R%d", reg, m.returnAddressRegister) + } + m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor + case frameRestoreExtended: // op: ULEB128 register + return 0, fmt.Errorf("unimplemented frameRestoreExtended") + case frameUndefined: // op: ULEB128 register; unimplemented + return 0, fmt.Errorf("unimplemented frameUndefined") + case frameSameValue: // op: ULEB128 register + return 0, fmt.Errorf("unimplemented frameSameValue") + case frameRegister: // op: ULEB128 register ULEB128 register + return 0, fmt.Errorf("unimplemented frameRegister") + case frameRememberState: + return 0, fmt.Errorf("unimplemented frameRememberState") + case frameRestoreState: + return 0, fmt.Errorf("unimplemented frameRestoreState") + case frameExpression: // op: ULEB128 register BLOCK + return 0, fmt.Errorf("unimplemented frameExpression") + case frameOffsetExtendedSf: // op: ULEB128 register SLEB128 offset + return 0, fmt.Errorf("unimplemented frameOffsetExtended_sf") + case frameValOffset: // op: ULEB128 ULEB128 + return 0, fmt.Errorf("unimplemented frameValOffset") + case frameValOffsetSf: // op: ULEB128 SLEB128 + return 0, fmt.Errorf("unimplemented frameValOffsetSf") + case frameValExpression: // op: ULEB128 BLOCK + return 0, fmt.Errorf("unimplemented frameValExpression") + + default: + if frameLoUser <= op && op <= frameHiUser { + return 0, fmt.Errorf("unknown user-defined frame op %#x", op) + } + return 0, fmt.Errorf("unknown frame op %#x", op) + } + } + return m.cfaOffset, nil +} diff --git a/vendor/golang.org/x/debug/dwarf/line.go b/vendor/golang.org/x/debug/dwarf/line.go new file mode 100644 index 0000000..2f47739 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/line.go @@ -0,0 +1,448 @@ +// 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 dwarf + +// This file implements the mapping from PC to lines. +// TODO: Find a way to test this properly. + +// http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.2 page 108 + +import ( + "fmt" + "sort" + "strings" +) + +// PCToLine returns the file and line number corresponding to the PC value. +// It returns an error if a correspondence cannot be found. +func (d *Data) PCToLine(pc uint64) (file string, line uint64, err error) { + c := d.pcToLineEntries + if len(c) == 0 { + return "", 0, fmt.Errorf("PCToLine: no line table") + } + i := sort.Search(len(c), func(i int) bool { return c[i].pc > pc }) - 1 + // c[i] is now the entry in pcToLineEntries with the largest pc that is not + // larger than the query pc. + // The search has failed if: + // - All pcs in c were larger than the query pc (i == -1). + // - c[i] marked the end of a sequence of instructions (c[i].file == 0). + // - c[i] is the last element of c, and isn't the end of a sequence of + // instructions, and the search pc is much larger than c[i].pc. In this + // case, we don't know the range of the last instruction, but the search + // pc is probably past it. + if i == -1 || c[i].file == 0 || (i+1 == len(c) && pc-c[i].pc > 1024) { + return "", 0, fmt.Errorf("no source line defined for PC %#x", pc) + } + if c[i].file >= uint64(len(d.sourceFiles)) { + return "", 0, fmt.Errorf("invalid file number in DWARF data") + } + return d.sourceFiles[c[i].file], c[i].line, nil +} + +// LineToBreakpointPCs returns the PCs that should be used as breakpoints +// corresponding to the given file and line number. +// It returns an empty slice if no PCs were found. +func (d *Data) LineToBreakpointPCs(file string, line uint64) ([]uint64, error) { + compDir := d.compilationDirectory() + + // Find the closest match in the executable for the specified file. + // We choose the file with the largest number of path components matching + // at the end of the name. If there is a tie, we prefer files that are + // under the compilation directory. If there is still a tie, we choose + // the file with the shortest name. + // TODO: handle duplicate file names in the DWARF? + var bestFile struct { + fileNum uint64 // Index of the file in the DWARF data. + components int // Number of matching path components. + length int // Length of the filename. + underComp bool // File is under the compilation directory. + } + for filenum, filename := range d.sourceFiles { + c := matchingPathComponentSuffixSize(filename, file) + underComp := strings.HasPrefix(filename, compDir) + better := false + if c != bestFile.components { + better = c > bestFile.components + } else if underComp != bestFile.underComp { + better = underComp + } else { + better = len(filename) < bestFile.length + } + if better { + bestFile.fileNum = uint64(filenum) + bestFile.components = c + bestFile.length = len(filename) + bestFile.underComp = underComp + } + } + if bestFile.components == 0 { + return nil, fmt.Errorf("couldn't find file %q", file) + } + + c := d.lineToPCEntries[bestFile.fileNum] + // c contains all (pc, line) pairs for the appropriate file. + start := sort.Search(len(c), func(i int) bool { return c[i].line >= line }) + end := sort.Search(len(c), func(i int) bool { return c[i].line > line }) + // c[i].line == line for all i in the range [start, end). + pcs := make([]uint64, 0, end-start) + for i := start; i < end; i++ { + pcs = append(pcs, c[i].pc) + } + return pcs, nil +} + +// compilationDirectory finds the first compilation unit entry in d and returns +// the compilation directory contained in it. +// If it fails, it returns the empty string. +func (d *Data) compilationDirectory() string { + r := d.Reader() + for { + entry, err := r.Next() + if entry == nil || err != nil { + return "" + } + if entry.Tag == TagCompileUnit { + name, _ := entry.Val(AttrCompDir).(string) + return name + } + } +} + +// matchingPathComponentSuffixSize returns the largest n such that the last n +// components of the paths p1 and p2 are equal. +// e.g. matchingPathComponentSuffixSize("a/b/x/y.go", "b/a/x/y.go") returns 2. +func matchingPathComponentSuffixSize(p1, p2 string) int { + // TODO: deal with other path separators. + c1 := strings.Split(p1, "/") + c2 := strings.Split(p2, "/") + min := len(c1) + if len(c2) < min { + min = len(c2) + } + var n int + for n = 0; n < min; n++ { + if c1[len(c1)-1-n] != c2[len(c2)-1-n] { + break + } + } + return n +} + +// Standard opcodes. Figure 37, page 178. +// If an opcode >= lineMachine.prologue.opcodeBase, it is a special +// opcode rather than the opcode defined in this table. +const ( + lineStdCopy = 0x01 + lineStdAdvancePC = 0x02 + lineStdAdvanceLine = 0x03 + lineStdSetFile = 0x04 + lineStdSetColumn = 0x05 + lineStdNegateStmt = 0x06 + lineStdSetBasicBlock = 0x07 + lineStdConstAddPC = 0x08 + lineStdFixedAdvancePC = 0x09 + lineStdSetPrologueEnd = 0x0a + lineStdSetEpilogueBegin = 0x0b + lineStdSetISA = 0x0c +) + +// Extended opcodes. Figure 38, page 179. +const ( + lineStartExtendedOpcode = 0x00 // Not defined as a named constant in the spec. + lineExtEndSequence = 0x01 + lineExtSetAddress = 0x02 + lineExtDefineFile = 0x03 + lineExtSetDiscriminator = 0x04 // New in version 4. + lineExtLoUser = 0x80 + lineExtHiUser = 0xff +) + +// lineHeader holds the information stored in the header of the line table for a +// single compilation unit. +// Section 6.2.4, page 112. +type lineHeader struct { + unitLength int + version int + headerLength int + minInstructionLength int + maxOpsPerInstruction int + defaultIsStmt bool + lineBase int + lineRange int + opcodeBase byte + stdOpcodeLengths []byte + include []string // entry 0 is empty; means current directory + file []lineFile // entry 0 is empty. +} + +// lineFile represents a file name stored in the PC/line table, usually in the header. +type lineFile struct { + name string + index int // index into include directories + time int // implementation-defined time of last modification + length int // length in bytes, 0 if not available. +} + +// lineMachine holds the registers evaluated during executing of the PC/line mapping engine. +// Section 6.2.2, page 109. +type lineMachine struct { + // The program-counter value corresponding to a machine instruction generated by the compiler. + address uint64 + + // An unsigned integer representing the index of an operation within a VLIW + // instruction. The index of the first operation is 0. For non-VLIW + // architectures, this register will always be 0. + // The address and op_index registers, taken together, form an operation + // pointer that can reference any individual operation with the instruction + // stream. + opIndex uint64 + + // An unsigned integer indicating the identity of the source file corresponding to a machine instruction. + file uint64 + + // An unsigned integer indicating a source line number. Lines are numbered + // beginning at 1. The compiler may emit the value 0 in cases where an + // instruction cannot be attributed to any source line. + line uint64 + + // An unsigned integer indicating a column number within a source line. + // Columns are numbered beginning at 1. The value 0 is reserved to indicate + // that a statement begins at the “left edge” of the line. + column uint64 + + // A boolean indicating that the current instruction is a recommended + // breakpoint location. A recommended breakpoint location is intended to + // “represent” a line, a statement and/or a semantically distinct subpart of a + // statement. + isStmt bool + + // A boolean indicating that the current instruction is the beginning of a basic + // block. + basicBlock bool + + // A boolean indicating that the current address is that of the first byte after + // the end of a sequence of target machine instructions. end_sequence + // terminates a sequence of lines; therefore other information in the same + // row is not meaningful. + endSequence bool + + // A boolean indicating that the current address is one (of possibly many) + // where execution should be suspended for an entry breakpoint of a + // function. + prologueEnd bool + + // A boolean indicating that the current address is one (of possibly many) + // where execution should be suspended for an exit breakpoint of a function. + epilogueBegin bool + + // An unsigned integer whose value encodes the applicable instruction set + // architecture for the current instruction. + // The encoding of instruction sets should be shared by all users of a given + // architecture. It is recommended that this encoding be defined by the ABI + // authoring committee for each architecture. + isa uint64 + + // An unsigned integer identifying the block to which the current instruction + // belongs. Discriminator values are assigned arbitrarily by the DWARF + // producer and serve to distinguish among multiple blocks that may all be + // associated with the same source file, line, and column. Where only one + // block exists for a given source position, the discriminator value should be + // zero. + discriminator uint64 + + // The header for the current compilation unit. + // Not an actual register, but stored here for cleanliness. + header lineHeader +} + +// parseHeader parses the header describing the compilation unit in the line +// table starting at the specified offset. +func (m *lineMachine) parseHeader(b *buf) error { + m.header = lineHeader{} + m.header.unitLength = int(b.uint32()) // Note: We are assuming 32-bit DWARF format. + if m.header.unitLength > len(b.data) { + return fmt.Errorf("DWARF: bad PC/line header length") + } + m.header.version = int(b.uint16()) + m.header.headerLength = int(b.uint32()) + m.header.minInstructionLength = int(b.uint8()) + if m.header.version >= 4 { + m.header.maxOpsPerInstruction = int(b.uint8()) + } else { + m.header.maxOpsPerInstruction = 1 + } + m.header.defaultIsStmt = b.uint8() != 0 + m.header.lineBase = int(int8(b.uint8())) + m.header.lineRange = int(b.uint8()) + m.header.opcodeBase = b.uint8() + m.header.stdOpcodeLengths = make([]byte, m.header.opcodeBase-1) + copy(m.header.stdOpcodeLengths, b.bytes(int(m.header.opcodeBase-1))) + m.header.include = make([]string, 1) // First entry is empty; file index entries are 1-indexed. + // Includes + for { + name := b.string() + if name == "" { + break + } + m.header.include = append(m.header.include, name) + } + // Files + m.header.file = make([]lineFile, 1, 10) // entries are 1-indexed in line number program. + for { + name := b.string() + if name == "" { + break + } + index := b.uint() + time := b.uint() + length := b.uint() + f := lineFile{ + name: name, + index: int(index), + time: int(time), + length: int(length), + } + m.header.file = append(m.header.file, f) + } + return nil +} + +// Special opcodes, page 117. +// There are seven steps to processing special opcodes. We break them up here +// because the caller needs to output a row between steps 2 and 4, and because +// we need to perform just step 2 for the opcode DW_LNS_const_add_pc. + +func (m *lineMachine) specialOpcodeStep1(opcode byte) { + adjustedOpcode := int(opcode - m.header.opcodeBase) + lineAdvance := m.header.lineBase + (adjustedOpcode % m.header.lineRange) + m.line += uint64(lineAdvance) +} + +func (m *lineMachine) specialOpcodeStep2(opcode byte) { + adjustedOpcode := int(opcode - m.header.opcodeBase) + advance := adjustedOpcode / m.header.lineRange + delta := (int(m.opIndex) + advance) / m.header.maxOpsPerInstruction + m.address += uint64(m.header.minInstructionLength * delta) + m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction) +} + +func (m *lineMachine) specialOpcodeSteps4To7() { + m.basicBlock = false + m.prologueEnd = false + m.epilogueBegin = false + m.discriminator = 0 +} + +// evalCompilationUnit reads the next compilation unit and calls f at each output row. +// Line machine execution continues while f returns true. +func (m *lineMachine) evalCompilationUnit(b *buf, f func(m *lineMachine) (cont bool)) error { + m.reset() + for len(b.data) > 0 { + op := b.uint8() + if op >= m.header.opcodeBase { + m.specialOpcodeStep1(op) + m.specialOpcodeStep2(op) + // Step 3 is to output a row, so we call f here. + if !f(m) { + return nil + } + m.specialOpcodeSteps4To7() + continue + } + switch op { + case lineStartExtendedOpcode: + if len(b.data) == 0 { + return fmt.Errorf("DWARF: short extended opcode (1)") + } + size := b.uint() + if uint64(len(b.data)) < size { + return fmt.Errorf("DWARF: short extended opcode (2)") + } + op = b.uint8() + switch op { + case lineExtEndSequence: + m.endSequence = true + if !f(m) { + return nil + } + if len(b.data) == 0 { + return nil + } + m.reset() + case lineExtSetAddress: + m.address = b.addr() + m.opIndex = 0 + case lineExtDefineFile: + return fmt.Errorf("DWARF: unimplemented define_file op") + case lineExtSetDiscriminator: + discriminator := b.uint() + m.discriminator = discriminator + default: + return fmt.Errorf("DWARF: unknown extended opcode %#x", op) + } + case lineStdCopy: + if !f(m) { + return nil + } + m.discriminator = 0 + m.basicBlock = false + m.prologueEnd = false + m.epilogueBegin = false + case lineStdAdvancePC: + advance := b.uint() + delta := (int(m.opIndex) + int(advance)) / m.header.maxOpsPerInstruction + m.address += uint64(m.header.minInstructionLength * delta) + m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction) + m.basicBlock = false + m.prologueEnd = false + m.epilogueBegin = false + m.discriminator = 0 + case lineStdAdvanceLine: + advance := b.int() + m.line = uint64(int64(m.line) + advance) + case lineStdSetFile: + index := b.uint() + m.file = index + case lineStdSetColumn: + column := b.uint() + m.column = column + case lineStdNegateStmt: + m.isStmt = !m.isStmt + case lineStdSetBasicBlock: + m.basicBlock = true + case lineStdFixedAdvancePC: + m.address += uint64(b.uint16()) + m.opIndex = 0 + case lineStdSetPrologueEnd: + m.prologueEnd = true + case lineStdSetEpilogueBegin: + m.epilogueBegin = true + case lineStdSetISA: + m.isa = b.uint() + case lineStdConstAddPC: + // Update the the address and op_index registers. + m.specialOpcodeStep2(255) + default: + panic("not reached") + } + } + return fmt.Errorf("DWARF: unexpected end of line number information") +} + +// reset sets the machine's registers to the initial state. Page 111. +func (m *lineMachine) reset() { + m.address = 0 + m.opIndex = 0 + m.file = 1 + m.line = 1 + m.column = 0 + m.isStmt = m.header.defaultIsStmt + m.basicBlock = false + m.endSequence = false + m.prologueEnd = false + m.epilogueBegin = false + m.isa = 0 + m.discriminator = 0 +} diff --git a/vendor/golang.org/x/debug/dwarf/open.go b/vendor/golang.org/x/debug/dwarf/open.go new file mode 100644 index 0000000..c727e8b --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/open.go @@ -0,0 +1,94 @@ +// 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 dwarf provides access to DWARF debugging information loaded from +// executable files, as defined in the DWARF 2.0 Standard at +// http://dwarfstd.org/doc/dwarf-2.0.0.pdf +package dwarf + +import "encoding/binary" + +// Data represents the DWARF debugging information +// loaded from an executable file (for example, an ELF or Mach-O executable). +type Data struct { + // raw data + abbrev []byte + aranges []byte + frame []byte + info []byte + line []byte + pubnames []byte + ranges []byte + str []byte + + // parsed data + abbrevCache map[uint32]abbrevTable + order binary.ByteOrder + typeCache map[Offset]Type + typeSigs map[uint64]*typeUnit + unit []unit + sourceFiles []string // source files listed in .debug_line. + nameCache // map from name to top-level entries in .debug_info. + pcToFuncEntries // cache of .debug_info data for function bounds. + pcToLineEntries // cache of .debug_line data, used for efficient PC-to-line mapping. + lineToPCEntries // cache of .debug_line data, used for efficient line-to-[]PC mapping. +} + +// New returns a new Data object initialized from the given parameters. +// Rather than calling this function directly, clients should typically use +// the DWARF method of the File type of the appropriate package debug/elf, +// debug/macho, or debug/pe. +// +// The []byte arguments are the data from the corresponding debug section +// in the object file; for example, for an ELF object, abbrev is the contents of +// the ".debug_abbrev" section. +func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) { + d := &Data{ + abbrev: abbrev, + aranges: aranges, + frame: frame, + info: info, + line: line, + pubnames: pubnames, + ranges: ranges, + 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. + // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3). + if len(d.info) < 6 { + return nil, DecodeError{"info", Offset(len(d.info)), "too short"} + } + x, y := d.info[4], d.info[5] + switch { + case x == 0 && y == 0: + return nil, DecodeError{"info", 4, "unsupported version 0"} + case x == 0: + d.order = binary.BigEndian + case y == 0: + d.order = binary.LittleEndian + default: + return nil, DecodeError{"info", 4, "cannot determine byte order"} + } + + u, err := d.parseUnits() + if err != nil { + return nil, err + } + d.unit = u + d.buildInfoCaches() + d.buildLineCaches() + 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/vendor/golang.org/x/debug/dwarf/symbol.go b/vendor/golang.org/x/debug/dwarf/symbol.go new file mode 100644 index 0000000..52d6829 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/symbol.go @@ -0,0 +1,119 @@ +// 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 dwarf + +// This file provides simple methods to access the symbol table by name and address. + +import ( + "fmt" + "regexp" + "sort" +) + +// lookupEntry returns the first Entry for the name. +// If tag is non-zero, only entries with that tag are considered. +func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) { + x, ok := d.nameCache[name] + if !ok { + return nil, fmt.Errorf("DWARF entry for %q not found", name) + } + for ; x != nil; x = x.link { + if tag == 0 || x.entry.Tag == tag { + return x.entry, nil + } + } + return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag) +} + +// LookupMatchingSymbols returns the names of all top-level entries matching +// the given regular expression. +func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) { + for name := range d.nameCache { + if nameRE.MatchString(name) { + result = append(result, name) + } + } + return result, nil +} + +// LookupEntry returns the Entry for the named symbol. +func (d *Data) LookupEntry(name string) (*Entry, error) { + return d.lookupEntry(name, 0) +} + +// LookupFunction returns the entry for a function. +func (d *Data) LookupFunction(name string) (*Entry, error) { + return d.lookupEntry(name, TagSubprogram) +} + +// LookupVariable returns the entry for a (global) variable. +func (d *Data) LookupVariable(name string) (*Entry, error) { + return d.lookupEntry(name, TagVariable) +} + +// EntryLocation returns the address of the object referred to by the given Entry. +func (d *Data) EntryLocation(e *Entry) (uint64, error) { + loc, _ := e.Val(AttrLocation).([]byte) + if len(loc) == 0 { + return 0, fmt.Errorf("DWARF entry has no Location attribute") + } + // TODO: implement the DWARF Location bytecode. What we have here only + // recognizes a program with a single literal opAddr bytecode. + if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize { + switch asize { + case 1: + return uint64(loc[1]), nil + case 2: + return uint64(d.order.Uint16(loc[1:])), nil + case 4: + return uint64(d.order.Uint32(loc[1:])), nil + case 8: + return d.order.Uint64(loc[1:]), nil + } + } + return 0, fmt.Errorf("DWARF entry has an unimplemented Location op") +} + +// EntryType returns the Type for an Entry. +func (d *Data) EntryType(e *Entry) (Type, error) { + off, err := d.EntryTypeOffset(e) + if err != nil { + return nil, err + } + return d.Type(off) +} + +// EntryTypeOffset returns the offset in the given Entry's type attribute. +func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) { + v := e.Val(AttrType) + if v == nil { + return 0, fmt.Errorf("DWARF entry has no Type attribute") + } + off, ok := v.(Offset) + if !ok { + return 0, fmt.Errorf("DWARF entry has an invalid Type attribute") + } + return off, nil +} + +// PCToFunction returns the entry and address for the function containing the +// specified PC. +func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) { + p := d.pcToFuncEntries + if len(p) == 0 { + return nil, 0, fmt.Errorf("no function addresses loaded") + } + i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1 + // The search failed if: + // - pc was before the start of any function. + // - The largest function bound not larger than pc was the end of a function, + // not the start of one. + // - The largest function bound not larger than pc was the start of a function + // that we don't know the end of, and the PC is much larger than the start. + if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) { + return nil, 0, fmt.Errorf("no function at %x", pc) + } + return p[i].entry, p[i].pc, nil +} diff --git a/vendor/golang.org/x/debug/dwarf/type.go b/vendor/golang.org/x/debug/dwarf/type.go new file mode 100644 index 0000000..ae1a3f3 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/type.go @@ -0,0 +1,862 @@ +// 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. + +// DWARF type information structures. +// The format is heavily biased toward C, but for simplicity +// the String methods use a pseudo-Go syntax. + +package dwarf + +import ( + "fmt" + "reflect" + "strconv" +) + +// A Type conventionally represents a pointer to any of the +// specific Type structures (CharType, StructType, etc.). +type Type interface { + Common() *CommonType + String() string + Size() int64 +} + +// A CommonType holds fields common to multiple types. +// If a field is not known or not applicable for a given type, +// the zero value is used. +type CommonType struct { + ByteSize int64 // size of value of this type, in bytes + Name string // name that can be used to refer to type + ReflectKind reflect.Kind // the reflect kind of the type. + Offset Offset // the offset at which this type was read +} + +func (c *CommonType) Common() *CommonType { return c } + +func (c *CommonType) Size() int64 { return c.ByteSize } + +// Basic types + +// A BasicType holds fields common to all basic types. +type BasicType struct { + CommonType + BitSize int64 + BitOffset int64 +} + +func (b *BasicType) Basic() *BasicType { return b } + +func (t *BasicType) String() string { + if t.Name != "" { + return t.Name + } + return "?" +} + +// A CharType represents a signed character type. +type CharType struct { + BasicType +} + +// A UcharType represents an unsigned character type. +type UcharType struct { + BasicType +} + +// An IntType represents a signed integer type. +type IntType struct { + BasicType +} + +// A UintType represents an unsigned integer type. +type UintType struct { + BasicType +} + +// A FloatType represents a floating point type. +type FloatType struct { + BasicType +} + +// A ComplexType represents a complex floating point type. +type ComplexType struct { + BasicType +} + +// A BoolType represents a boolean type. +type BoolType struct { + BasicType +} + +// An AddrType represents a machine address type. +type AddrType struct { + BasicType +} + +// An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type. +type UnspecifiedType struct { + BasicType +} + +// qualifiers + +// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier. +type QualType struct { + CommonType + Qual string + Type Type +} + +func (t *QualType) String() string { return t.Qual + " " + t.Type.String() } + +func (t *QualType) Size() int64 { return t.Type.Size() } + +// An ArrayType represents a fixed size array type. +type ArrayType struct { + CommonType + Type Type + StrideBitSize int64 // if > 0, number of bits to hold each element + Count int64 // if == -1, an incomplete array, like char x[]. +} + +func (t *ArrayType) String() string { + return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String() +} + +func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() } + +// A VoidType represents the C void type. +type VoidType struct { + CommonType +} + +func (t *VoidType) String() string { return "void" } + +// A PtrType represents a pointer type. +type PtrType struct { + CommonType + Type Type +} + +func (t *PtrType) String() string { return "*" + t.Type.String() } + +// A StructType represents a struct, union, or C++ class type. +type StructType struct { + CommonType + StructName string + Kind string // "struct", "union", or "class". + Field []*StructField + Incomplete bool // if true, struct, union, class is declared but not defined +} + +// A StructField represents a field in a struct, union, or C++ class type. +type StructField struct { + Name string + Type Type + ByteOffset int64 + ByteSize int64 + BitOffset int64 // within the ByteSize bytes at ByteOffset + BitSize int64 // zero if not a bit field +} + +func (t *StructType) String() string { + if t.StructName != "" { + return t.Kind + " " + t.StructName + } + return t.Defn() +} + +func (t *StructType) Defn() string { + s := t.Kind + if t.StructName != "" { + s += " " + t.StructName + } + if t.Incomplete { + s += " /*incomplete*/" + return s + } + s += " {" + for i, f := range t.Field { + if i > 0 { + s += "; " + } + s += f.Name + " " + f.Type.String() + s += "@" + strconv.FormatInt(f.ByteOffset, 10) + if f.BitSize > 0 { + s += " : " + strconv.FormatInt(f.BitSize, 10) + s += "@" + strconv.FormatInt(f.BitOffset, 10) + } + } + s += "}" + return s +} + +// A SliceType represents a Go slice type. It looks like a StructType, describing +// the runtime-internal structure, with extra fields. +type SliceType struct { + StructType + ElemType Type +} + +func (t *SliceType) String() string { + if t.Name != "" { + return t.Name + } + return "[]" + t.ElemType.String() +} + +// A StringType represents a Go string type. It looks like a StructType, describing +// the runtime-internal structure, but we wrap it for neatness. +type StringType struct { + StructType +} + +func (t *StringType) String() string { + if t.Name != "" { + return t.Name + } + return "string" +} + +// An InterfaceType represents a Go interface. +type InterfaceType struct { + TypedefType +} + +func (t *InterfaceType) String() string { + if t.Name != "" { + return t.Name + } + return "Interface" +} + +// An EnumType represents an enumerated type. +// The only indication of its native integer type is its ByteSize +// (inside CommonType). +type EnumType struct { + CommonType + EnumName string + Val []*EnumValue +} + +// An EnumValue represents a single enumeration value. +type EnumValue struct { + Name string + Val int64 +} + +func (t *EnumType) String() string { + s := "enum" + if t.EnumName != "" { + s += " " + t.EnumName + } + s += " {" + for i, v := range t.Val { + if i > 0 { + s += "; " + } + s += v.Name + "=" + strconv.FormatInt(v.Val, 10) + } + s += "}" + return s +} + +// A FuncType represents a function type. +type FuncType struct { + CommonType + ReturnType Type + ParamType []Type +} + +func (t *FuncType) String() string { + s := "func(" + for i, t := range t.ParamType { + if i > 0 { + s += ", " + } + s += t.String() + } + s += ")" + if t.ReturnType != nil { + s += " " + t.ReturnType.String() + } + return s +} + +// A DotDotDotType represents the variadic ... function parameter. +type DotDotDotType struct { + CommonType +} + +func (t *DotDotDotType) String() string { return "..." } + +// A TypedefType represents a named type. +type TypedefType struct { + CommonType + Type Type +} + +func (t *TypedefType) String() string { return t.Name } + +func (t *TypedefType) Size() int64 { return t.Type.Size() } + +// A MapType represents a Go map type. It looks like a TypedefType, describing +// the runtime-internal structure, with extra fields. +type MapType struct { + TypedefType + KeyType Type + ElemType Type +} + +func (t *MapType) String() string { + if t.Name != "" { + return t.Name + } + return "map[" + t.KeyType.String() + "]" + t.ElemType.String() +} + +// A ChanType represents a Go channel type. +type ChanType struct { + TypedefType + ElemType Type +} + +func (t *ChanType) String() string { + if t.Name != "" { + return t.Name + } + return "chan " + t.ElemType.String() +} + +// 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 + // AddressSize returns the size in bytes of addresses in the current + // compilation unit. + AddressSize() int +} + +// Type reads the type at off in the DWARF ``info'' section. +func (d *Data) Type(off Offset) (Type, error) { + return d.readType("info", d.Reader(), off, d.typeCache) +} + +func getKind(e *Entry) reflect.Kind { + integer, _ := e.Val(AttrGoKind).(int64) + return reflect.Kind(integer) +} + +// 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.Seek(off) + e, err := r.Next() + if err != nil { + return nil, err + } + addressSize := r.AddressSize() + if e == nil || e.Offset != off { + return nil, DecodeError{name, off, "no type at offset"} + } + + // Parse type from Entry. + // Must always set typeCache[off] before calling + // d.Type recursively, to handle circular types correctly. + var typ Type + + nextDepth := 0 + + // Get next child; set err if error happens. + next := func() *Entry { + if !e.Children { + return nil + } + // Only return direct children. + // Skip over composite entries that happen to be nested + // inside this one. Most DWARF generators wouldn't generate + // such a thing, but clang does. + // See golang.org/issue/6472. + for { + kid, err1 := r.Next() + if err1 != nil { + err = err1 + return nil + } + if kid == nil { + err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"} + return nil + } + if kid.Tag == 0 { + if nextDepth > 0 { + nextDepth-- + continue + } + return nil + } + if kid.Children { + nextDepth++ + } + if nextDepth > 0 { + continue + } + return kid + } + } + + // Get Type referred to by Entry's attr. + // Set err if error happens. Not having a type is an error. + typeOf := func(e *Entry, attr Attr) Type { + tval := e.Val(attr) + 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) + } + return t + } + + switch e.Tag { + case TagArrayType: + // Multi-dimensional array. (DWARF v2 §5.4) + // Attributes: + // AttrType:subtype [required] + // AttrStrideSize: distance in bits between each element of the array + // AttrStride: distance in bytes between each element of the array + // AttrByteSize: size of entire array + // Children: + // TagSubrangeType or TagEnumerationType giving one dimension. + // dimensions are in left to right order. + t := new(ArrayType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if t.Type = typeOf(e, AttrType); err != nil { + goto Error + } + if bytes, ok := e.Val(AttrStride).(int64); ok { + t.StrideBitSize = 8 * bytes + } else if bits, ok := e.Val(AttrStrideSize).(int64); ok { + t.StrideBitSize = bits + } else { + // If there's no stride specified, assume it's the size of the + // array's element type. + t.StrideBitSize = 8 * t.Type.Size() + } + + // Accumulate dimensions, + ndim := 0 + for kid := next(); kid != nil; kid = next() { + // TODO(rsc): Can also be TagEnumerationType + // but haven't seen that in the wild yet. + switch kid.Tag { + case TagSubrangeType: + count, ok := kid.Val(AttrCount).(int64) + if !ok { + // Old binaries may have an upper bound instead. + count, ok = kid.Val(AttrUpperBound).(int64) + if ok { + count++ // Length is one more than upper bound. + } else { + count = -1 // As in x[]. + } + } + if ndim == 0 { + t.Count = count + } else { + // Multidimensional array. + // Create new array type underneath this one. + t.Type = &ArrayType{Type: t.Type, Count: count} + } + ndim++ + case TagEnumerationType: + err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"} + goto Error + } + } + if ndim == 0 { + // LLVM generates this for x[]. + t.Count = -1 + } + + case TagBaseType: + // Basic type. (DWARF v2 §5.1) + // Attributes: + // AttrName: name of base type in programming language of the compilation unit [required] + // AttrEncoding: encoding value for type (encFloat etc) [required] + // AttrByteSize: size of type in bytes [required] + // AttrBitOffset: for sub-byte types, size in bits + // AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes + name, _ := e.Val(AttrName).(string) + enc, ok := e.Val(AttrEncoding).(int64) + if !ok { + err = DecodeError{name, e.Offset, "missing encoding attribute for " + name} + goto Error + } + switch enc { + default: + err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"} + goto Error + + case encAddress: + typ = new(AddrType) + case encBoolean: + typ = new(BoolType) + case encComplexFloat: + typ = new(ComplexType) + if name == "complex" { + // clang writes out 'complex' instead of 'complex float' or 'complex double'. + // clang also writes out a byte size that we can use to distinguish. + // See issue 8694. + switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize { + case 8: + name = "complex float" + case 16: + name = "complex double" + } + } + case encFloat: + typ = new(FloatType) + case encSigned: + typ = new(IntType) + case encUnsigned: + typ = new(UintType) + case encSignedChar: + typ = new(CharType) + case encUnsignedChar: + typ = new(UcharType) + } + typeCache[off] = typ + t := typ.(interface { + Basic() *BasicType + }).Basic() + t.Name = name + t.BitSize, _ = e.Val(AttrBitSize).(int64) + t.BitOffset, _ = e.Val(AttrBitOffset).(int64) + t.ReflectKind = getKind(e) + + case TagClassType, TagStructType, TagUnionType: + // Structure, union, or class type. (DWARF v2 §5.5) + // Also Slices and Strings (Go-specific). + // Attributes: + // AttrName: name of struct, union, or class + // AttrByteSize: byte size [required] + // AttrDeclaration: if true, struct/union/class is incomplete + // AttrGoElem: present for slices only. + // Children: + // TagMember to describe one member. + // AttrName: name of member [required] + // AttrType: type of member [required] + // AttrByteSize: size in bytes + // AttrBitOffset: bit offset within bytes for bit fields + // AttrBitSize: bit size for bit fields + // AttrDataMemberLoc: location within struct [required for struct, class] + // There is much more to handle C++, all ignored for now. + t := new(StructType) + t.ReflectKind = getKind(e) + switch t.ReflectKind { + case reflect.Slice: + slice := new(SliceType) + slice.ElemType = typeOf(e, AttrGoElem) + t = &slice.StructType + typ = slice + case reflect.String: + str := new(StringType) + t = &str.StructType + typ = str + default: + typ = t + } + typeCache[off] = typ + switch e.Tag { + case TagClassType: + t.Kind = "class" + case TagStructType: + t.Kind = "struct" + case TagUnionType: + t.Kind = "union" + } + t.Name, _ = e.Val(AttrName).(string) + t.StructName, _ = e.Val(AttrName).(string) + t.Incomplete = e.Val(AttrDeclaration) != nil + t.Field = make([]*StructField, 0, 8) + var lastFieldType Type + var lastFieldBitOffset int64 + for kid := next(); kid != nil; kid = next() { + if kid.Tag == TagMember { + f := new(StructField) + if f.Type = typeOf(kid, AttrType); err != nil { + goto Error + } + switch loc := kid.Val(AttrDataMemberLoc).(type) { + case []byte: + // TODO: Should have original compilation + // unit here, not unknownFormat. + if len(loc) == 0 { + // Empty exprloc. f.ByteOffset=0. + break + } + b := makeBuf(d, unknownFormat{}, "location", 0, loc) + op := b.uint8() + switch op { + case opPlusUconst: + // Handle opcode sequence [DW_OP_plus_uconst ] + f.ByteOffset = int64(b.uint()) + b.assertEmpty() + case opConsts: + // Handle opcode sequence [DW_OP_consts DW_OP_plus] + f.ByteOffset = b.int() + op = b.uint8() + if op != opPlus { + err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)} + goto Error + } + b.assertEmpty() + default: + err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)} + goto Error + } + if b.err != nil { + err = b.err + goto Error + } + case int64: + f.ByteOffset = loc + } + + haveBitOffset := false + f.Name, _ = kid.Val(AttrName).(string) + f.ByteSize, _ = kid.Val(AttrByteSize).(int64) + f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) + f.BitSize, _ = kid.Val(AttrBitSize).(int64) + t.Field = append(t.Field, f) + + bito := f.BitOffset + if !haveBitOffset { + bito = f.ByteOffset * 8 + } + if bito == lastFieldBitOffset && t.Kind != "union" { + // Last field was zero width. Fix array length. + // (DWARF writes out 0-length arrays as if they were 1-length arrays.) + zeroArray(lastFieldType) + } + lastFieldType = f.Type + lastFieldBitOffset = bito + } + } + if t.Kind != "union" { + b, ok := e.Val(AttrByteSize).(int64) + if ok && b*8 == lastFieldBitOffset { + // Final field must be zero width. Fix array length. + zeroArray(lastFieldType) + } + } + + case TagConstType, TagVolatileType, TagRestrictType: + // Type modifier (DWARF v2 §5.2) + // Attributes: + // AttrType: subtype + t := new(QualType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if t.Type = typeOf(e, AttrType); err != nil { + goto Error + } + switch e.Tag { + case TagConstType: + t.Qual = "const" + case TagRestrictType: + t.Qual = "restrict" + case TagVolatileType: + t.Qual = "volatile" + } + + case TagEnumerationType: + // Enumeration type (DWARF v2 §5.6) + // Attributes: + // AttrName: enum name if any + // AttrByteSize: bytes required to represent largest value + // Children: + // TagEnumerator: + // AttrName: name of constant + // AttrConstValue: value of constant + t := new(EnumType) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + t.Name, _ = e.Val(AttrName).(string) + t.EnumName, _ = e.Val(AttrName).(string) + t.Val = make([]*EnumValue, 0, 8) + for kid := next(); kid != nil; kid = next() { + if kid.Tag == TagEnumerator { + f := new(EnumValue) + f.Name, _ = kid.Val(AttrName).(string) + f.Val, _ = kid.Val(AttrConstValue).(int64) + n := len(t.Val) + if n >= cap(t.Val) { + val := make([]*EnumValue, n, n*2) + copy(val, t.Val) + t.Val = val + } + t.Val = t.Val[0 : n+1] + t.Val[n] = f + } + } + + case TagPointerType: + // Type modifier (DWARF v2 §5.2) + // Attributes: + // AttrType: subtype [not required! void* has no AttrType] + // AttrAddrClass: address class [ignored] + t := new(PtrType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if e.Val(AttrType) == nil { + t.Type = &VoidType{} + break + } + t.Type = typeOf(e, AttrType) + + case TagSubroutineType: + // Subroutine type. (DWARF v2 §5.7) + // Attributes: + // AttrType: type of return value if any + // AttrName: possible name of type [ignored] + // AttrPrototyped: whether used ANSI C prototype [ignored] + // Children: + // TagFormalParameter: typed parameter + // AttrType: type of parameter + // TagUnspecifiedParameter: final ... + t := new(FuncType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if t.ReturnType = typeOf(e, AttrType); err != nil { + goto Error + } + t.ParamType = make([]Type, 0, 8) + for kid := next(); kid != nil; kid = next() { + var tkid Type + switch kid.Tag { + default: + continue + case TagFormalParameter: + if tkid = typeOf(kid, AttrType); err != nil { + goto Error + } + case TagUnspecifiedParameters: + tkid = &DotDotDotType{} + } + t.ParamType = append(t.ParamType, tkid) + } + + case TagTypedef: + // Typedef (DWARF v2 §5.3) + // Also maps and channels (Go-specific). + // Attributes: + // AttrName: name [required] + // AttrType: type definition [required] + // AttrGoKey: present for maps. + // AttrGoElem: present for maps and channels. + t := new(TypedefType) + t.ReflectKind = getKind(e) + switch t.ReflectKind { + case reflect.Map: + m := new(MapType) + m.KeyType = typeOf(e, AttrGoKey) + m.ElemType = typeOf(e, AttrGoElem) + t = &m.TypedefType + typ = m + case reflect.Chan: + c := new(ChanType) + c.ElemType = typeOf(e, AttrGoElem) + t = &c.TypedefType + typ = c + case reflect.Interface: + it := new(InterfaceType) + t = &it.TypedefType + typ = it + default: + typ = t + } + typeCache[off] = typ + t.Name, _ = e.Val(AttrName).(string) + t.Type = typeOf(e, AttrType) + + case TagUnspecifiedType: + // Unspecified type (DWARF v3 §5.2) + // Attributes: + // AttrName: name + t := new(UnspecifiedType) + typ = t + typeCache[off] = t + t.Name, _ = e.Val(AttrName).(string) + } + + if err != nil { + goto Error + } + + typ.Common().Offset = off + + { + b, ok := e.Val(AttrByteSize).(int64) + if !ok { + b = -1 + switch t := typ.(type) { + case *TypedefType: + b = t.Type.Size() + case *MapType: + b = t.Type.Size() + case *ChanType: + b = t.Type.Size() + case *InterfaceType: + b = t.Type.Size() + case *PtrType: + b = int64(addressSize) + } + } + typ.Common().ByteSize = b + } + return typ, nil + +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(typeCache, off) + return nil, err +} + +func zeroArray(t Type) { + for { + at, ok := t.(*ArrayType) + if !ok { + break + } + at.Count = 0 + t = at.Type + } +} diff --git a/vendor/golang.org/x/debug/dwarf/typeunit.go b/vendor/golang.org/x/debug/dwarf/typeunit.go new file mode 100644 index 0000000..d93b9f5 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/typeunit.go @@ -0,0 +1,171 @@ +// 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:]) +} + +// AddressSize returns the size in bytes of addresses in the current type unit. +func (tur *typeUnitReader) AddressSize() int { + return tur.tu.unit.asize +} + +// 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/vendor/golang.org/x/debug/dwarf/unit.go b/vendor/golang.org/x/debug/dwarf/unit.go new file mode 100644 index 0000000..0fbc8e0 --- /dev/null +++ b/vendor/golang.org/x/debug/dwarf/unit.go @@ -0,0 +1,90 @@ +// 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 dwarf + +import "strconv" + +// DWARF debug info is split into a sequence of compilation units. +// Each unit has its own abbreviation table and address size. + +type unit struct { + base Offset // byte offset of header within the aggregate info + off Offset // byte offset of data within the aggregate info + data []byte + atable abbrevTable + asize int + vers int + is64 bool // True for 64-bit DWARF format +} + +// Implement the dataFormat interface. + +func (u *unit) version() int { + return u.vers +} + +func (u *unit) dwarf64() (bool, bool) { + return u.is64, true +} + +func (u *unit) addrsize() int { + return u.asize +} + +func (d *Data) parseUnits() ([]unit, error) { + // Count units. + nunit := 0 + b := makeBuf(d, unknownFormat{}, "info", 0, d.info) + for len(b.data) > 0 { + len := b.uint32() + if len == 0xffffffff { + len64 := b.uint64() + if len64 != uint64(uint32(len64)) { + b.error("unit length overflow") + break + } + len = uint32(len64) + } + b.skip(int(len)) + nunit++ + } + if b.err != nil { + return nil, b.err + } + + // Again, this time writing them down. + b = makeBuf(d, unknownFormat{}, "info", 0, d.info) + units := make([]unit, nunit) + for i := range units { + u := &units[i] + u.base = b.off + n := b.uint32() + if n == 0xffffffff { + u.is64 = true + n = uint32(b.uint64()) + } + vers := b.uint16() + if vers != 2 && vers != 3 && vers != 4 { + b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) + break + } + u.vers = int(vers) + atable, err := d.parseAbbrev(b.uint32()) + if err != nil { + if b.err == nil { + b.err = err + } + break + } + u.atable = atable + u.asize = int(b.uint8()) + u.off = b.off + u.data = b.bytes(int(n - (2 + 4 + 1))) + } + if b.err != nil { + return nil, b.err + } + return units, nil +} diff --git a/vendor/golang.org/x/debug/elf/elf.go b/vendor/golang.org/x/debug/elf/elf.go new file mode 100644 index 0000000..03e42b0 --- /dev/null +++ b/vendor/golang.org/x/debug/elf/elf.go @@ -0,0 +1,1521 @@ +/* + * ELF constants and data structures + * + * Derived from: + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ + * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ + * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ + * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ + * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ + * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ + * + * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. + * Copyright (c) 2001 David E. O'Brien + * Portions Copyright 2009 The Go Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +package elf + +import "strconv" + +/* + * Constants + */ + +// Indexes into the Header.Ident array. +const ( + EI_CLASS = 4 /* Class of machine. */ + EI_DATA = 5 /* Data format. */ + EI_VERSION = 6 /* ELF format version. */ + EI_OSABI = 7 /* Operating system / ABI identification */ + EI_ABIVERSION = 8 /* ABI version */ + EI_PAD = 9 /* Start of padding (per SVR4 ABI). */ + EI_NIDENT = 16 /* Size of e_ident array. */ +) + +// Initial magic number for ELF files. +const ELFMAG = "\177ELF" + +// Version is found in Header.Ident[EI_VERSION] and Header.Version. +type Version byte + +const ( + EV_NONE Version = 0 + EV_CURRENT Version = 1 +) + +var versionStrings = []intName{ + {0, "EV_NONE"}, + {1, "EV_CURRENT"}, +} + +func (i Version) String() string { return stringName(uint32(i), versionStrings, false) } +func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) } + +// Class is found in Header.Ident[EI_CLASS] and Header.Class. +type Class byte + +const ( + ELFCLASSNONE Class = 0 /* Unknown class. */ + ELFCLASS32 Class = 1 /* 32-bit architecture. */ + ELFCLASS64 Class = 2 /* 64-bit architecture. */ +) + +var classStrings = []intName{ + {0, "ELFCLASSNONE"}, + {1, "ELFCLASS32"}, + {2, "ELFCLASS64"}, +} + +func (i Class) String() string { return stringName(uint32(i), classStrings, false) } +func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) } + +// Data is found in Header.Ident[EI_DATA] and Header.Data. +type Data byte + +const ( + ELFDATANONE Data = 0 /* Unknown data format. */ + ELFDATA2LSB Data = 1 /* 2's complement little-endian. */ + ELFDATA2MSB Data = 2 /* 2's complement big-endian. */ +) + +var dataStrings = []intName{ + {0, "ELFDATANONE"}, + {1, "ELFDATA2LSB"}, + {2, "ELFDATA2MSB"}, +} + +func (i Data) String() string { return stringName(uint32(i), dataStrings, false) } +func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) } + +// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI. +type OSABI byte + +const ( + ELFOSABI_NONE OSABI = 0 /* UNIX System V ABI */ + ELFOSABI_HPUX OSABI = 1 /* HP-UX operating system */ + ELFOSABI_NETBSD OSABI = 2 /* NetBSD */ + ELFOSABI_LINUX OSABI = 3 /* GNU/Linux */ + ELFOSABI_HURD OSABI = 4 /* GNU/Hurd */ + ELFOSABI_86OPEN OSABI = 5 /* 86Open common IA32 ABI */ + ELFOSABI_SOLARIS OSABI = 6 /* Solaris */ + ELFOSABI_AIX OSABI = 7 /* AIX */ + ELFOSABI_IRIX OSABI = 8 /* IRIX */ + ELFOSABI_FREEBSD OSABI = 9 /* FreeBSD */ + ELFOSABI_TRU64 OSABI = 10 /* TRU64 UNIX */ + ELFOSABI_MODESTO OSABI = 11 /* Novell Modesto */ + ELFOSABI_OPENBSD OSABI = 12 /* OpenBSD */ + ELFOSABI_OPENVMS OSABI = 13 /* Open VMS */ + ELFOSABI_NSK OSABI = 14 /* HP Non-Stop Kernel */ + ELFOSABI_ARM OSABI = 97 /* ARM */ + ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */ +) + +var osabiStrings = []intName{ + {0, "ELFOSABI_NONE"}, + {1, "ELFOSABI_HPUX"}, + {2, "ELFOSABI_NETBSD"}, + {3, "ELFOSABI_LINUX"}, + {4, "ELFOSABI_HURD"}, + {5, "ELFOSABI_86OPEN"}, + {6, "ELFOSABI_SOLARIS"}, + {7, "ELFOSABI_AIX"}, + {8, "ELFOSABI_IRIX"}, + {9, "ELFOSABI_FREEBSD"}, + {10, "ELFOSABI_TRU64"}, + {11, "ELFOSABI_MODESTO"}, + {12, "ELFOSABI_OPENBSD"}, + {13, "ELFOSABI_OPENVMS"}, + {14, "ELFOSABI_NSK"}, + {97, "ELFOSABI_ARM"}, + {255, "ELFOSABI_STANDALONE"}, +} + +func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) } +func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) } + +// Type is found in Header.Type. +type Type uint16 + +const ( + ET_NONE Type = 0 /* Unknown type. */ + ET_REL Type = 1 /* Relocatable. */ + ET_EXEC Type = 2 /* Executable. */ + ET_DYN Type = 3 /* Shared object. */ + ET_CORE Type = 4 /* Core file. */ + ET_LOOS Type = 0xfe00 /* First operating system specific. */ + ET_HIOS Type = 0xfeff /* Last operating system-specific. */ + ET_LOPROC Type = 0xff00 /* First processor-specific. */ + ET_HIPROC Type = 0xffff /* Last processor-specific. */ +) + +var typeStrings = []intName{ + {0, "ET_NONE"}, + {1, "ET_REL"}, + {2, "ET_EXEC"}, + {3, "ET_DYN"}, + {4, "ET_CORE"}, + {0xfe00, "ET_LOOS"}, + {0xfeff, "ET_HIOS"}, + {0xff00, "ET_LOPROC"}, + {0xffff, "ET_HIPROC"}, +} + +func (i Type) String() string { return stringName(uint32(i), typeStrings, false) } +func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) } + +// Machine is found in Header.Machine. +type Machine uint16 + +const ( + EM_NONE Machine = 0 /* Unknown machine. */ + EM_M32 Machine = 1 /* AT&T WE32100. */ + EM_SPARC Machine = 2 /* Sun SPARC. */ + EM_386 Machine = 3 /* Intel i386. */ + EM_68K Machine = 4 /* Motorola 68000. */ + EM_88K Machine = 5 /* Motorola 88000. */ + EM_860 Machine = 7 /* Intel i860. */ + EM_MIPS Machine = 8 /* MIPS R3000 Big-Endian only. */ + EM_S370 Machine = 9 /* IBM System/370. */ + EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */ + EM_PARISC Machine = 15 /* HP PA-RISC. */ + EM_VPP500 Machine = 17 /* Fujitsu VPP500. */ + EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */ + EM_960 Machine = 19 /* Intel 80960. */ + EM_PPC Machine = 20 /* PowerPC 32-bit. */ + EM_PPC64 Machine = 21 /* PowerPC 64-bit. */ + EM_S390 Machine = 22 /* IBM System/390. */ + EM_V800 Machine = 36 /* NEC V800. */ + EM_FR20 Machine = 37 /* Fujitsu FR20. */ + EM_RH32 Machine = 38 /* TRW RH-32. */ + EM_RCE Machine = 39 /* Motorola RCE. */ + EM_ARM Machine = 40 /* ARM. */ + EM_SH Machine = 42 /* Hitachi SH. */ + EM_SPARCV9 Machine = 43 /* SPARC v9 64-bit. */ + EM_TRICORE Machine = 44 /* Siemens TriCore embedded processor. */ + EM_ARC Machine = 45 /* Argonaut RISC Core. */ + EM_H8_300 Machine = 46 /* Hitachi H8/300. */ + EM_H8_300H Machine = 47 /* Hitachi H8/300H. */ + EM_H8S Machine = 48 /* Hitachi H8S. */ + EM_H8_500 Machine = 49 /* Hitachi H8/500. */ + EM_IA_64 Machine = 50 /* Intel IA-64 Processor. */ + EM_MIPS_X Machine = 51 /* Stanford MIPS-X. */ + EM_COLDFIRE Machine = 52 /* Motorola ColdFire. */ + EM_68HC12 Machine = 53 /* Motorola M68HC12. */ + EM_MMA Machine = 54 /* Fujitsu MMA. */ + EM_PCP Machine = 55 /* Siemens PCP. */ + EM_NCPU Machine = 56 /* Sony nCPU. */ + EM_NDR1 Machine = 57 /* Denso NDR1 microprocessor. */ + EM_STARCORE Machine = 58 /* Motorola Star*Core processor. */ + EM_ME16 Machine = 59 /* Toyota ME16 processor. */ + EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */ + EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */ + EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */ + + /* Non-standard or deprecated. */ + EM_486 Machine = 6 /* Intel i486. */ + EM_MIPS_RS4_BE Machine = 10 /* MIPS R4000 Big-Endian */ + EM_ALPHA_STD Machine = 41 /* Digital Alpha (standard value). */ + EM_ALPHA Machine = 0x9026 /* Alpha (written in the absence of an ABI) */ +) + +var machineStrings = []intName{ + {0, "EM_NONE"}, + {1, "EM_M32"}, + {2, "EM_SPARC"}, + {3, "EM_386"}, + {4, "EM_68K"}, + {5, "EM_88K"}, + {7, "EM_860"}, + {8, "EM_MIPS"}, + {9, "EM_S370"}, + {10, "EM_MIPS_RS3_LE"}, + {15, "EM_PARISC"}, + {17, "EM_VPP500"}, + {18, "EM_SPARC32PLUS"}, + {19, "EM_960"}, + {20, "EM_PPC"}, + {21, "EM_PPC64"}, + {22, "EM_S390"}, + {36, "EM_V800"}, + {37, "EM_FR20"}, + {38, "EM_RH32"}, + {39, "EM_RCE"}, + {40, "EM_ARM"}, + {42, "EM_SH"}, + {43, "EM_SPARCV9"}, + {44, "EM_TRICORE"}, + {45, "EM_ARC"}, + {46, "EM_H8_300"}, + {47, "EM_H8_300H"}, + {48, "EM_H8S"}, + {49, "EM_H8_500"}, + {50, "EM_IA_64"}, + {51, "EM_MIPS_X"}, + {52, "EM_COLDFIRE"}, + {53, "EM_68HC12"}, + {54, "EM_MMA"}, + {55, "EM_PCP"}, + {56, "EM_NCPU"}, + {57, "EM_NDR1"}, + {58, "EM_STARCORE"}, + {59, "EM_ME16"}, + {60, "EM_ST100"}, + {61, "EM_TINYJ"}, + {62, "EM_X86_64"}, + + /* Non-standard or deprecated. */ + {6, "EM_486"}, + {10, "EM_MIPS_RS4_BE"}, + {41, "EM_ALPHA_STD"}, + {0x9026, "EM_ALPHA"}, +} + +func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) } +func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) } + +// Special section indices. +type SectionIndex int + +const ( + SHN_UNDEF SectionIndex = 0 /* Undefined, missing, irrelevant. */ + SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */ + SHN_LOPROC SectionIndex = 0xff00 /* First processor-specific. */ + SHN_HIPROC SectionIndex = 0xff1f /* Last processor-specific. */ + SHN_LOOS SectionIndex = 0xff20 /* First operating system-specific. */ + SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */ + SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */ + SHN_COMMON SectionIndex = 0xfff2 /* Common data. */ + SHN_XINDEX SectionIndex = 0xffff /* Escape -- index stored elsewhere. */ + SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */ +) + +var shnStrings = []intName{ + {0, "SHN_UNDEF"}, + {0xff00, "SHN_LOPROC"}, + {0xff20, "SHN_LOOS"}, + {0xfff1, "SHN_ABS"}, + {0xfff2, "SHN_COMMON"}, + {0xffff, "SHN_XINDEX"}, +} + +func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) } +func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) } + +// Section type. +type SectionType uint32 + +const ( + SHT_NULL SectionType = 0 /* inactive */ + SHT_PROGBITS SectionType = 1 /* program defined information */ + SHT_SYMTAB SectionType = 2 /* symbol table section */ + SHT_STRTAB SectionType = 3 /* string table section */ + SHT_RELA SectionType = 4 /* relocation section with addends */ + SHT_HASH SectionType = 5 /* symbol hash table section */ + SHT_DYNAMIC SectionType = 6 /* dynamic section */ + SHT_NOTE SectionType = 7 /* note section */ + SHT_NOBITS SectionType = 8 /* no space section */ + SHT_REL SectionType = 9 /* relocation section - no addends */ + SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */ + SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */ + SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */ + SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */ + SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */ + SHT_GROUP SectionType = 17 /* Section group. */ + SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */ + SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */ + SHT_GNU_ATTRIBUTES SectionType = 0x6ffffff5 /* GNU object attributes */ + SHT_GNU_HASH SectionType = 0x6ffffff6 /* GNU hash table */ + SHT_GNU_LIBLIST SectionType = 0x6ffffff7 /* GNU prelink library list */ + SHT_GNU_VERDEF SectionType = 0x6ffffffd /* GNU version definition section */ + SHT_GNU_VERNEED SectionType = 0x6ffffffe /* GNU version needs section */ + SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */ + SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */ + SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */ + SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */ + SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */ + SHT_HIUSER SectionType = 0xffffffff /* specific indexes */ +) + +var shtStrings = []intName{ + {0, "SHT_NULL"}, + {1, "SHT_PROGBITS"}, + {2, "SHT_SYMTAB"}, + {3, "SHT_STRTAB"}, + {4, "SHT_RELA"}, + {5, "SHT_HASH"}, + {6, "SHT_DYNAMIC"}, + {7, "SHT_NOTE"}, + {8, "SHT_NOBITS"}, + {9, "SHT_REL"}, + {10, "SHT_SHLIB"}, + {11, "SHT_DYNSYM"}, + {14, "SHT_INIT_ARRAY"}, + {15, "SHT_FINI_ARRAY"}, + {16, "SHT_PREINIT_ARRAY"}, + {17, "SHT_GROUP"}, + {18, "SHT_SYMTAB_SHNDX"}, + {0x60000000, "SHT_LOOS"}, + {0x6ffffff5, "SHT_GNU_ATTRIBUTES"}, + {0x6ffffff6, "SHT_GNU_HASH"}, + {0x6ffffff7, "SHT_GNU_LIBLIST"}, + {0x6ffffffd, "SHT_GNU_VERDEF"}, + {0x6ffffffe, "SHT_GNU_VERNEED"}, + {0x6fffffff, "SHT_GNU_VERSYM"}, + {0x70000000, "SHT_LOPROC"}, + {0x7fffffff, "SHT_HIPROC"}, + {0x80000000, "SHT_LOUSER"}, + {0xffffffff, "SHT_HIUSER"}, +} + +func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) } +func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) } + +// Section flags. +type SectionFlag uint32 + +const ( + SHF_WRITE SectionFlag = 0x1 /* Section contains writable data. */ + SHF_ALLOC SectionFlag = 0x2 /* Section occupies memory. */ + SHF_EXECINSTR SectionFlag = 0x4 /* Section contains instructions. */ + SHF_MERGE SectionFlag = 0x10 /* Section may be merged. */ + SHF_STRINGS SectionFlag = 0x20 /* Section contains strings. */ + SHF_INFO_LINK SectionFlag = 0x40 /* sh_info holds section index. */ + SHF_LINK_ORDER SectionFlag = 0x80 /* Special ordering requirements. */ + SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */ + SHF_GROUP SectionFlag = 0x200 /* Member of section group. */ + SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */ + SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */ + SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */ +) + +var shfStrings = []intName{ + {0x1, "SHF_WRITE"}, + {0x2, "SHF_ALLOC"}, + {0x4, "SHF_EXECINSTR"}, + {0x10, "SHF_MERGE"}, + {0x20, "SHF_STRINGS"}, + {0x40, "SHF_INFO_LINK"}, + {0x80, "SHF_LINK_ORDER"}, + {0x100, "SHF_OS_NONCONFORMING"}, + {0x200, "SHF_GROUP"}, + {0x400, "SHF_TLS"}, +} + +func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) } +func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) } + +// Prog.Type +type ProgType int + +const ( + PT_NULL ProgType = 0 /* Unused entry. */ + PT_LOAD ProgType = 1 /* Loadable segment. */ + PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */ + PT_INTERP ProgType = 3 /* Pathname of interpreter. */ + PT_NOTE ProgType = 4 /* Auxiliary information. */ + PT_SHLIB ProgType = 5 /* Reserved (not used). */ + PT_PHDR ProgType = 6 /* Location of program header itself. */ + PT_TLS ProgType = 7 /* Thread local storage segment */ + PT_LOOS ProgType = 0x60000000 /* First OS-specific. */ + PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */ + PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */ + PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */ +) + +var ptStrings = []intName{ + {0, "PT_NULL"}, + {1, "PT_LOAD"}, + {2, "PT_DYNAMIC"}, + {3, "PT_INTERP"}, + {4, "PT_NOTE"}, + {5, "PT_SHLIB"}, + {6, "PT_PHDR"}, + {7, "PT_TLS"}, + {0x60000000, "PT_LOOS"}, + {0x6fffffff, "PT_HIOS"}, + {0x70000000, "PT_LOPROC"}, + {0x7fffffff, "PT_HIPROC"}, +} + +func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) } +func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) } + +// Prog.Flag +type ProgFlag uint32 + +const ( + PF_X ProgFlag = 0x1 /* Executable. */ + PF_W ProgFlag = 0x2 /* Writable. */ + PF_R ProgFlag = 0x4 /* Readable. */ + PF_MASKOS ProgFlag = 0x0ff00000 /* Operating system-specific. */ + PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */ +) + +var pfStrings = []intName{ + {0x1, "PF_X"}, + {0x2, "PF_W"}, + {0x4, "PF_R"}, +} + +func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) } +func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) } + +// Dyn.Tag +type DynTag int + +const ( + DT_NULL DynTag = 0 /* Terminating entry. */ + DT_NEEDED DynTag = 1 /* String table offset of a needed shared library. */ + DT_PLTRELSZ DynTag = 2 /* Total size in bytes of PLT relocations. */ + DT_PLTGOT DynTag = 3 /* Processor-dependent address. */ + DT_HASH DynTag = 4 /* Address of symbol hash table. */ + DT_STRTAB DynTag = 5 /* Address of string table. */ + DT_SYMTAB DynTag = 6 /* Address of symbol table. */ + DT_RELA DynTag = 7 /* Address of ElfNN_Rela relocations. */ + DT_RELASZ DynTag = 8 /* Total size of ElfNN_Rela relocations. */ + DT_RELAENT DynTag = 9 /* Size of each ElfNN_Rela relocation entry. */ + DT_STRSZ DynTag = 10 /* Size of string table. */ + DT_SYMENT DynTag = 11 /* Size of each symbol table entry. */ + DT_INIT DynTag = 12 /* Address of initialization function. */ + DT_FINI DynTag = 13 /* Address of finalization function. */ + DT_SONAME DynTag = 14 /* String table offset of shared object name. */ + DT_RPATH DynTag = 15 /* String table offset of library path. [sup] */ + DT_SYMBOLIC DynTag = 16 /* Indicates "symbolic" linking. [sup] */ + DT_REL DynTag = 17 /* Address of ElfNN_Rel relocations. */ + DT_RELSZ DynTag = 18 /* Total size of ElfNN_Rel relocations. */ + DT_RELENT DynTag = 19 /* Size of each ElfNN_Rel relocation. */ + DT_PLTREL DynTag = 20 /* Type of relocation used for PLT. */ + DT_DEBUG DynTag = 21 /* Reserved (not used). */ + DT_TEXTREL DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */ + DT_JMPREL DynTag = 23 /* Address of PLT relocations. */ + DT_BIND_NOW DynTag = 24 /* [sup] */ + 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_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 + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ + DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */ + DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */ + DT_LOOS DynTag = 0x6000000d /* First OS-specific */ + DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */ + DT_VERSYM DynTag = 0x6ffffff0 + DT_VERNEED DynTag = 0x6ffffffe + DT_VERNEEDNUM DynTag = 0x6fffffff + DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */ + DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */ +) + +var dtStrings = []intName{ + {0, "DT_NULL"}, + {1, "DT_NEEDED"}, + {2, "DT_PLTRELSZ"}, + {3, "DT_PLTGOT"}, + {4, "DT_HASH"}, + {5, "DT_STRTAB"}, + {6, "DT_SYMTAB"}, + {7, "DT_RELA"}, + {8, "DT_RELASZ"}, + {9, "DT_RELAENT"}, + {10, "DT_STRSZ"}, + {11, "DT_SYMENT"}, + {12, "DT_INIT"}, + {13, "DT_FINI"}, + {14, "DT_SONAME"}, + {15, "DT_RPATH"}, + {16, "DT_SYMBOLIC"}, + {17, "DT_REL"}, + {18, "DT_RELSZ"}, + {19, "DT_RELENT"}, + {20, "DT_PLTREL"}, + {21, "DT_DEBUG"}, + {22, "DT_TEXTREL"}, + {23, "DT_JMPREL"}, + {24, "DT_BIND_NOW"}, + {25, "DT_INIT_ARRAY"}, + {26, "DT_FINI_ARRAY"}, + {27, "DT_INIT_ARRAYSZ"}, + {28, "DT_FINI_ARRAYSZ"}, + {29, "DT_RUNPATH"}, + {30, "DT_FLAGS"}, + {32, "DT_ENCODING"}, + {32, "DT_PREINIT_ARRAY"}, + {33, "DT_PREINIT_ARRAYSZ"}, + {0x6000000d, "DT_LOOS"}, + {0x6ffff000, "DT_HIOS"}, + {0x6ffffff0, "DT_VERSYM"}, + {0x6ffffffe, "DT_VERNEED"}, + {0x6fffffff, "DT_VERNEEDNUM"}, + {0x70000000, "DT_LOPROC"}, + {0x7fffffff, "DT_HIPROC"}, +} + +func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) } +func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) } + +// DT_FLAGS values. +type DynFlag int + +const ( + DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may + make reference to the + $ORIGIN substitution string */ + DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */ + DF_TEXTREL DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */ + DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ + DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ +) + +var dflagStrings = []intName{ + {0x0001, "DF_ORIGIN"}, + {0x0002, "DF_SYMBOLIC"}, + {0x0004, "DF_TEXTREL"}, + {0x0008, "DF_BIND_NOW"}, + {0x0010, "DF_STATIC_TLS"}, +} + +func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) } +func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) } + +// NType values; used in core files. +type NType int + +const ( + NT_PRSTATUS NType = 1 /* Process status. */ + NT_FPREGSET NType = 2 /* Floating point registers. */ + NT_PRPSINFO NType = 3 /* Process state info. */ +) + +var ntypeStrings = []intName{ + {1, "NT_PRSTATUS"}, + {2, "NT_FPREGSET"}, + {3, "NT_PRPSINFO"}, +} + +func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) } +func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) } + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +type SymBind int + +const ( + STB_LOCAL SymBind = 0 /* Local symbol */ + STB_GLOBAL SymBind = 1 /* Global symbol */ + STB_WEAK SymBind = 2 /* like global - lower precedence */ + STB_LOOS SymBind = 10 /* Reserved range for operating system */ + STB_HIOS SymBind = 12 /* specific semantics. */ + STB_LOPROC SymBind = 13 /* reserved range for processor */ + STB_HIPROC SymBind = 15 /* specific semantics. */ +) + +var stbStrings = []intName{ + {0, "STB_LOCAL"}, + {1, "STB_GLOBAL"}, + {2, "STB_WEAK"}, + {10, "STB_LOOS"}, + {12, "STB_HIOS"}, + {13, "STB_LOPROC"}, + {15, "STB_HIPROC"}, +} + +func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) } +func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) } + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +type SymType int + +const ( + STT_NOTYPE SymType = 0 /* Unspecified type. */ + STT_OBJECT SymType = 1 /* Data object. */ + STT_FUNC SymType = 2 /* Function. */ + STT_SECTION SymType = 3 /* Section. */ + STT_FILE SymType = 4 /* Source file. */ + STT_COMMON SymType = 5 /* Uninitialized common block. */ + STT_TLS SymType = 6 /* TLS object. */ + STT_LOOS SymType = 10 /* Reserved range for operating system */ + STT_HIOS SymType = 12 /* specific semantics. */ + STT_LOPROC SymType = 13 /* reserved range for processor */ + STT_HIPROC SymType = 15 /* specific semantics. */ +) + +var sttStrings = []intName{ + {0, "STT_NOTYPE"}, + {1, "STT_OBJECT"}, + {2, "STT_FUNC"}, + {3, "STT_SECTION"}, + {4, "STT_FILE"}, + {5, "STT_COMMON"}, + {6, "STT_TLS"}, + {10, "STT_LOOS"}, + {12, "STT_HIOS"}, + {13, "STT_LOPROC"}, + {15, "STT_HIPROC"}, +} + +func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) } +func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) } + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +type SymVis int + +const ( + STV_DEFAULT SymVis = 0x0 /* Default visibility (see binding). */ + STV_INTERNAL SymVis = 0x1 /* Special meaning in relocatable objects. */ + STV_HIDDEN SymVis = 0x2 /* Not visible. */ + STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */ +) + +var stvStrings = []intName{ + {0x0, "STV_DEFAULT"}, + {0x1, "STV_INTERNAL"}, + {0x2, "STV_HIDDEN"}, + {0x3, "STV_PROTECTED"}, +} + +func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) } +func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) } + +/* + * Relocation types. + */ + +// Relocation types for x86-64. +type R_X86_64 int + +const ( + R_X86_64_NONE R_X86_64 = 0 /* No relocation. */ + R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */ + R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */ + R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */ + R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */ + R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */ + R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */ + R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */ + R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */ + R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */ + R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */ + R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */ + R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */ + R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */ + R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */ + R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */ + R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */ + R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */ + R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */ + R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */ + R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */ + R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */ + R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */ + R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */ +) + +var rx86_64Strings = []intName{ + {0, "R_X86_64_NONE"}, + {1, "R_X86_64_64"}, + {2, "R_X86_64_PC32"}, + {3, "R_X86_64_GOT32"}, + {4, "R_X86_64_PLT32"}, + {5, "R_X86_64_COPY"}, + {6, "R_X86_64_GLOB_DAT"}, + {7, "R_X86_64_JMP_SLOT"}, + {8, "R_X86_64_RELATIVE"}, + {9, "R_X86_64_GOTPCREL"}, + {10, "R_X86_64_32"}, + {11, "R_X86_64_32S"}, + {12, "R_X86_64_16"}, + {13, "R_X86_64_PC16"}, + {14, "R_X86_64_8"}, + {15, "R_X86_64_PC8"}, + {16, "R_X86_64_DTPMOD64"}, + {17, "R_X86_64_DTPOFF64"}, + {18, "R_X86_64_TPOFF64"}, + {19, "R_X86_64_TLSGD"}, + {20, "R_X86_64_TLSLD"}, + {21, "R_X86_64_DTPOFF32"}, + {22, "R_X86_64_GOTTPOFF"}, + {23, "R_X86_64_TPOFF32"}, +} + +func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) } +func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) } + +// Relocation types for Alpha. +type R_ALPHA int + +const ( + R_ALPHA_NONE R_ALPHA = 0 /* No reloc */ + R_ALPHA_REFLONG R_ALPHA = 1 /* Direct 32 bit */ + R_ALPHA_REFQUAD R_ALPHA = 2 /* Direct 64 bit */ + R_ALPHA_GPREL32 R_ALPHA = 3 /* GP relative 32 bit */ + R_ALPHA_LITERAL R_ALPHA = 4 /* GP relative 16 bit w/optimization */ + R_ALPHA_LITUSE R_ALPHA = 5 /* Optimization hint for LITERAL */ + R_ALPHA_GPDISP R_ALPHA = 6 /* Add displacement to GP */ + R_ALPHA_BRADDR R_ALPHA = 7 /* PC+4 relative 23 bit shifted */ + R_ALPHA_HINT R_ALPHA = 8 /* PC+4 relative 16 bit shifted */ + R_ALPHA_SREL16 R_ALPHA = 9 /* PC relative 16 bit */ + R_ALPHA_SREL32 R_ALPHA = 10 /* PC relative 32 bit */ + R_ALPHA_SREL64 R_ALPHA = 11 /* PC relative 64 bit */ + R_ALPHA_OP_PUSH R_ALPHA = 12 /* OP stack push */ + R_ALPHA_OP_STORE R_ALPHA = 13 /* OP stack pop and store */ + R_ALPHA_OP_PSUB R_ALPHA = 14 /* OP stack subtract */ + R_ALPHA_OP_PRSHIFT R_ALPHA = 15 /* OP stack right shift */ + R_ALPHA_GPVALUE R_ALPHA = 16 + R_ALPHA_GPRELHIGH R_ALPHA = 17 + R_ALPHA_GPRELLOW R_ALPHA = 18 + R_ALPHA_IMMED_GP_16 R_ALPHA = 19 + R_ALPHA_IMMED_GP_HI32 R_ALPHA = 20 + R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21 + R_ALPHA_IMMED_BR_HI32 R_ALPHA = 22 + R_ALPHA_IMMED_LO32 R_ALPHA = 23 + R_ALPHA_COPY R_ALPHA = 24 /* Copy symbol at runtime */ + R_ALPHA_GLOB_DAT R_ALPHA = 25 /* Create GOT entry */ + R_ALPHA_JMP_SLOT R_ALPHA = 26 /* Create PLT entry */ + R_ALPHA_RELATIVE R_ALPHA = 27 /* Adjust by program base */ +) + +var ralphaStrings = []intName{ + {0, "R_ALPHA_NONE"}, + {1, "R_ALPHA_REFLONG"}, + {2, "R_ALPHA_REFQUAD"}, + {3, "R_ALPHA_GPREL32"}, + {4, "R_ALPHA_LITERAL"}, + {5, "R_ALPHA_LITUSE"}, + {6, "R_ALPHA_GPDISP"}, + {7, "R_ALPHA_BRADDR"}, + {8, "R_ALPHA_HINT"}, + {9, "R_ALPHA_SREL16"}, + {10, "R_ALPHA_SREL32"}, + {11, "R_ALPHA_SREL64"}, + {12, "R_ALPHA_OP_PUSH"}, + {13, "R_ALPHA_OP_STORE"}, + {14, "R_ALPHA_OP_PSUB"}, + {15, "R_ALPHA_OP_PRSHIFT"}, + {16, "R_ALPHA_GPVALUE"}, + {17, "R_ALPHA_GPRELHIGH"}, + {18, "R_ALPHA_GPRELLOW"}, + {19, "R_ALPHA_IMMED_GP_16"}, + {20, "R_ALPHA_IMMED_GP_HI32"}, + {21, "R_ALPHA_IMMED_SCN_HI32"}, + {22, "R_ALPHA_IMMED_BR_HI32"}, + {23, "R_ALPHA_IMMED_LO32"}, + {24, "R_ALPHA_COPY"}, + {25, "R_ALPHA_GLOB_DAT"}, + {26, "R_ALPHA_JMP_SLOT"}, + {27, "R_ALPHA_RELATIVE"}, +} + +func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) } +func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) } + +// Relocation types for ARM. +type R_ARM int + +const ( + R_ARM_NONE R_ARM = 0 /* No relocation. */ + R_ARM_PC24 R_ARM = 1 + R_ARM_ABS32 R_ARM = 2 + R_ARM_REL32 R_ARM = 3 + R_ARM_PC13 R_ARM = 4 + R_ARM_ABS16 R_ARM = 5 + R_ARM_ABS12 R_ARM = 6 + R_ARM_THM_ABS5 R_ARM = 7 + R_ARM_ABS8 R_ARM = 8 + R_ARM_SBREL32 R_ARM = 9 + R_ARM_THM_PC22 R_ARM = 10 + R_ARM_THM_PC8 R_ARM = 11 + R_ARM_AMP_VCALL9 R_ARM = 12 + R_ARM_SWI24 R_ARM = 13 + R_ARM_THM_SWI8 R_ARM = 14 + R_ARM_XPC25 R_ARM = 15 + R_ARM_THM_XPC22 R_ARM = 16 + R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */ + R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */ + R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */ + R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */ + R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */ + R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */ + R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */ + R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */ + R_ARM_GNU_VTENTRY R_ARM = 100 + R_ARM_GNU_VTINHERIT R_ARM = 101 + R_ARM_RSBREL32 R_ARM = 250 + R_ARM_THM_RPC22 R_ARM = 251 + R_ARM_RREL32 R_ARM = 252 + R_ARM_RABS32 R_ARM = 253 + R_ARM_RPC24 R_ARM = 254 + R_ARM_RBASE R_ARM = 255 +) + +var rarmStrings = []intName{ + {0, "R_ARM_NONE"}, + {1, "R_ARM_PC24"}, + {2, "R_ARM_ABS32"}, + {3, "R_ARM_REL32"}, + {4, "R_ARM_PC13"}, + {5, "R_ARM_ABS16"}, + {6, "R_ARM_ABS12"}, + {7, "R_ARM_THM_ABS5"}, + {8, "R_ARM_ABS8"}, + {9, "R_ARM_SBREL32"}, + {10, "R_ARM_THM_PC22"}, + {11, "R_ARM_THM_PC8"}, + {12, "R_ARM_AMP_VCALL9"}, + {13, "R_ARM_SWI24"}, + {14, "R_ARM_THM_SWI8"}, + {15, "R_ARM_XPC25"}, + {16, "R_ARM_THM_XPC22"}, + {20, "R_ARM_COPY"}, + {21, "R_ARM_GLOB_DAT"}, + {22, "R_ARM_JUMP_SLOT"}, + {23, "R_ARM_RELATIVE"}, + {24, "R_ARM_GOTOFF"}, + {25, "R_ARM_GOTPC"}, + {26, "R_ARM_GOT32"}, + {27, "R_ARM_PLT32"}, + {100, "R_ARM_GNU_VTENTRY"}, + {101, "R_ARM_GNU_VTINHERIT"}, + {250, "R_ARM_RSBREL32"}, + {251, "R_ARM_THM_RPC22"}, + {252, "R_ARM_RREL32"}, + {253, "R_ARM_RABS32"}, + {254, "R_ARM_RPC24"}, + {255, "R_ARM_RBASE"}, +} + +func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) } +func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) } + +// Relocation types for 386. +type R_386 int + +const ( + R_386_NONE R_386 = 0 /* No relocation. */ + R_386_32 R_386 = 1 /* Add symbol value. */ + R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */ + R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */ + R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */ + R_386_COPY R_386 = 5 /* Copy data from shared object. */ + R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */ + R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */ + R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */ + R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */ + R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */ + R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */ + R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */ + R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */ + R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */ + R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */ + R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */ + R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */ + R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */ + R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */ + R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */ + R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */ + R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */ + R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */ + R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */ + R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */ + R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */ +) + +var r386Strings = []intName{ + {0, "R_386_NONE"}, + {1, "R_386_32"}, + {2, "R_386_PC32"}, + {3, "R_386_GOT32"}, + {4, "R_386_PLT32"}, + {5, "R_386_COPY"}, + {6, "R_386_GLOB_DAT"}, + {7, "R_386_JMP_SLOT"}, + {8, "R_386_RELATIVE"}, + {9, "R_386_GOTOFF"}, + {10, "R_386_GOTPC"}, + {14, "R_386_TLS_TPOFF"}, + {15, "R_386_TLS_IE"}, + {16, "R_386_TLS_GOTIE"}, + {17, "R_386_TLS_LE"}, + {18, "R_386_TLS_GD"}, + {19, "R_386_TLS_LDM"}, + {24, "R_386_TLS_GD_32"}, + {25, "R_386_TLS_GD_PUSH"}, + {26, "R_386_TLS_GD_CALL"}, + {27, "R_386_TLS_GD_POP"}, + {28, "R_386_TLS_LDM_32"}, + {29, "R_386_TLS_LDM_PUSH"}, + {30, "R_386_TLS_LDM_CALL"}, + {31, "R_386_TLS_LDM_POP"}, + {32, "R_386_TLS_LDO_32"}, + {33, "R_386_TLS_IE_32"}, + {34, "R_386_TLS_LE_32"}, + {35, "R_386_TLS_DTPMOD32"}, + {36, "R_386_TLS_DTPOFF32"}, + {37, "R_386_TLS_TPOFF32"}, +} + +func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) } +func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) } + +// Relocation types for PowerPC. +type R_PPC int + +const ( + R_PPC_NONE R_PPC = 0 /* No relocation. */ + R_PPC_ADDR32 R_PPC = 1 + R_PPC_ADDR24 R_PPC = 2 + R_PPC_ADDR16 R_PPC = 3 + R_PPC_ADDR16_LO R_PPC = 4 + R_PPC_ADDR16_HI R_PPC = 5 + R_PPC_ADDR16_HA R_PPC = 6 + R_PPC_ADDR14 R_PPC = 7 + R_PPC_ADDR14_BRTAKEN R_PPC = 8 + R_PPC_ADDR14_BRNTAKEN R_PPC = 9 + R_PPC_REL24 R_PPC = 10 + R_PPC_REL14 R_PPC = 11 + R_PPC_REL14_BRTAKEN R_PPC = 12 + R_PPC_REL14_BRNTAKEN R_PPC = 13 + R_PPC_GOT16 R_PPC = 14 + R_PPC_GOT16_LO R_PPC = 15 + R_PPC_GOT16_HI R_PPC = 16 + R_PPC_GOT16_HA R_PPC = 17 + R_PPC_PLTREL24 R_PPC = 18 + R_PPC_COPY R_PPC = 19 + R_PPC_GLOB_DAT R_PPC = 20 + R_PPC_JMP_SLOT R_PPC = 21 + R_PPC_RELATIVE R_PPC = 22 + R_PPC_LOCAL24PC R_PPC = 23 + R_PPC_UADDR32 R_PPC = 24 + R_PPC_UADDR16 R_PPC = 25 + R_PPC_REL32 R_PPC = 26 + R_PPC_PLT32 R_PPC = 27 + R_PPC_PLTREL32 R_PPC = 28 + R_PPC_PLT16_LO R_PPC = 29 + R_PPC_PLT16_HI R_PPC = 30 + R_PPC_PLT16_HA R_PPC = 31 + R_PPC_SDAREL16 R_PPC = 32 + R_PPC_SECTOFF R_PPC = 33 + R_PPC_SECTOFF_LO R_PPC = 34 + R_PPC_SECTOFF_HI R_PPC = 35 + R_PPC_SECTOFF_HA R_PPC = 36 + R_PPC_TLS R_PPC = 67 + R_PPC_DTPMOD32 R_PPC = 68 + R_PPC_TPREL16 R_PPC = 69 + R_PPC_TPREL16_LO R_PPC = 70 + R_PPC_TPREL16_HI R_PPC = 71 + R_PPC_TPREL16_HA R_PPC = 72 + R_PPC_TPREL32 R_PPC = 73 + R_PPC_DTPREL16 R_PPC = 74 + R_PPC_DTPREL16_LO R_PPC = 75 + R_PPC_DTPREL16_HI R_PPC = 76 + R_PPC_DTPREL16_HA R_PPC = 77 + R_PPC_DTPREL32 R_PPC = 78 + R_PPC_GOT_TLSGD16 R_PPC = 79 + R_PPC_GOT_TLSGD16_LO R_PPC = 80 + R_PPC_GOT_TLSGD16_HI R_PPC = 81 + R_PPC_GOT_TLSGD16_HA R_PPC = 82 + R_PPC_GOT_TLSLD16 R_PPC = 83 + R_PPC_GOT_TLSLD16_LO R_PPC = 84 + R_PPC_GOT_TLSLD16_HI R_PPC = 85 + R_PPC_GOT_TLSLD16_HA R_PPC = 86 + R_PPC_GOT_TPREL16 R_PPC = 87 + R_PPC_GOT_TPREL16_LO R_PPC = 88 + R_PPC_GOT_TPREL16_HI R_PPC = 89 + R_PPC_GOT_TPREL16_HA R_PPC = 90 + R_PPC_EMB_NADDR32 R_PPC = 101 + R_PPC_EMB_NADDR16 R_PPC = 102 + R_PPC_EMB_NADDR16_LO R_PPC = 103 + R_PPC_EMB_NADDR16_HI R_PPC = 104 + R_PPC_EMB_NADDR16_HA R_PPC = 105 + R_PPC_EMB_SDAI16 R_PPC = 106 + R_PPC_EMB_SDA2I16 R_PPC = 107 + R_PPC_EMB_SDA2REL R_PPC = 108 + R_PPC_EMB_SDA21 R_PPC = 109 + R_PPC_EMB_MRKREF R_PPC = 110 + R_PPC_EMB_RELSEC16 R_PPC = 111 + R_PPC_EMB_RELST_LO R_PPC = 112 + R_PPC_EMB_RELST_HI R_PPC = 113 + R_PPC_EMB_RELST_HA R_PPC = 114 + R_PPC_EMB_BIT_FLD R_PPC = 115 + R_PPC_EMB_RELSDA R_PPC = 116 +) + +var rppcStrings = []intName{ + {0, "R_PPC_NONE"}, + {1, "R_PPC_ADDR32"}, + {2, "R_PPC_ADDR24"}, + {3, "R_PPC_ADDR16"}, + {4, "R_PPC_ADDR16_LO"}, + {5, "R_PPC_ADDR16_HI"}, + {6, "R_PPC_ADDR16_HA"}, + {7, "R_PPC_ADDR14"}, + {8, "R_PPC_ADDR14_BRTAKEN"}, + {9, "R_PPC_ADDR14_BRNTAKEN"}, + {10, "R_PPC_REL24"}, + {11, "R_PPC_REL14"}, + {12, "R_PPC_REL14_BRTAKEN"}, + {13, "R_PPC_REL14_BRNTAKEN"}, + {14, "R_PPC_GOT16"}, + {15, "R_PPC_GOT16_LO"}, + {16, "R_PPC_GOT16_HI"}, + {17, "R_PPC_GOT16_HA"}, + {18, "R_PPC_PLTREL24"}, + {19, "R_PPC_COPY"}, + {20, "R_PPC_GLOB_DAT"}, + {21, "R_PPC_JMP_SLOT"}, + {22, "R_PPC_RELATIVE"}, + {23, "R_PPC_LOCAL24PC"}, + {24, "R_PPC_UADDR32"}, + {25, "R_PPC_UADDR16"}, + {26, "R_PPC_REL32"}, + {27, "R_PPC_PLT32"}, + {28, "R_PPC_PLTREL32"}, + {29, "R_PPC_PLT16_LO"}, + {30, "R_PPC_PLT16_HI"}, + {31, "R_PPC_PLT16_HA"}, + {32, "R_PPC_SDAREL16"}, + {33, "R_PPC_SECTOFF"}, + {34, "R_PPC_SECTOFF_LO"}, + {35, "R_PPC_SECTOFF_HI"}, + {36, "R_PPC_SECTOFF_HA"}, + + {67, "R_PPC_TLS"}, + {68, "R_PPC_DTPMOD32"}, + {69, "R_PPC_TPREL16"}, + {70, "R_PPC_TPREL16_LO"}, + {71, "R_PPC_TPREL16_HI"}, + {72, "R_PPC_TPREL16_HA"}, + {73, "R_PPC_TPREL32"}, + {74, "R_PPC_DTPREL16"}, + {75, "R_PPC_DTPREL16_LO"}, + {76, "R_PPC_DTPREL16_HI"}, + {77, "R_PPC_DTPREL16_HA"}, + {78, "R_PPC_DTPREL32"}, + {79, "R_PPC_GOT_TLSGD16"}, + {80, "R_PPC_GOT_TLSGD16_LO"}, + {81, "R_PPC_GOT_TLSGD16_HI"}, + {82, "R_PPC_GOT_TLSGD16_HA"}, + {83, "R_PPC_GOT_TLSLD16"}, + {84, "R_PPC_GOT_TLSLD16_LO"}, + {85, "R_PPC_GOT_TLSLD16_HI"}, + {86, "R_PPC_GOT_TLSLD16_HA"}, + {87, "R_PPC_GOT_TPREL16"}, + {88, "R_PPC_GOT_TPREL16_LO"}, + {89, "R_PPC_GOT_TPREL16_HI"}, + {90, "R_PPC_GOT_TPREL16_HA"}, + + {101, "R_PPC_EMB_NADDR32"}, + {102, "R_PPC_EMB_NADDR16"}, + {103, "R_PPC_EMB_NADDR16_LO"}, + {104, "R_PPC_EMB_NADDR16_HI"}, + {105, "R_PPC_EMB_NADDR16_HA"}, + {106, "R_PPC_EMB_SDAI16"}, + {107, "R_PPC_EMB_SDA2I16"}, + {108, "R_PPC_EMB_SDA2REL"}, + {109, "R_PPC_EMB_SDA21"}, + {110, "R_PPC_EMB_MRKREF"}, + {111, "R_PPC_EMB_RELSEC16"}, + {112, "R_PPC_EMB_RELST_LO"}, + {113, "R_PPC_EMB_RELST_HI"}, + {114, "R_PPC_EMB_RELST_HA"}, + {115, "R_PPC_EMB_BIT_FLD"}, + {116, "R_PPC_EMB_RELSDA"}, +} + +func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) } +func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) } + +// Relocation types for SPARC. +type R_SPARC int + +const ( + R_SPARC_NONE R_SPARC = 0 + R_SPARC_8 R_SPARC = 1 + R_SPARC_16 R_SPARC = 2 + R_SPARC_32 R_SPARC = 3 + R_SPARC_DISP8 R_SPARC = 4 + R_SPARC_DISP16 R_SPARC = 5 + R_SPARC_DISP32 R_SPARC = 6 + R_SPARC_WDISP30 R_SPARC = 7 + R_SPARC_WDISP22 R_SPARC = 8 + R_SPARC_HI22 R_SPARC = 9 + R_SPARC_22 R_SPARC = 10 + R_SPARC_13 R_SPARC = 11 + R_SPARC_LO10 R_SPARC = 12 + R_SPARC_GOT10 R_SPARC = 13 + R_SPARC_GOT13 R_SPARC = 14 + R_SPARC_GOT22 R_SPARC = 15 + R_SPARC_PC10 R_SPARC = 16 + R_SPARC_PC22 R_SPARC = 17 + R_SPARC_WPLT30 R_SPARC = 18 + R_SPARC_COPY R_SPARC = 19 + R_SPARC_GLOB_DAT R_SPARC = 20 + R_SPARC_JMP_SLOT R_SPARC = 21 + R_SPARC_RELATIVE R_SPARC = 22 + R_SPARC_UA32 R_SPARC = 23 + R_SPARC_PLT32 R_SPARC = 24 + R_SPARC_HIPLT22 R_SPARC = 25 + R_SPARC_LOPLT10 R_SPARC = 26 + R_SPARC_PCPLT32 R_SPARC = 27 + R_SPARC_PCPLT22 R_SPARC = 28 + R_SPARC_PCPLT10 R_SPARC = 29 + R_SPARC_10 R_SPARC = 30 + R_SPARC_11 R_SPARC = 31 + R_SPARC_64 R_SPARC = 32 + R_SPARC_OLO10 R_SPARC = 33 + R_SPARC_HH22 R_SPARC = 34 + R_SPARC_HM10 R_SPARC = 35 + R_SPARC_LM22 R_SPARC = 36 + R_SPARC_PC_HH22 R_SPARC = 37 + R_SPARC_PC_HM10 R_SPARC = 38 + R_SPARC_PC_LM22 R_SPARC = 39 + R_SPARC_WDISP16 R_SPARC = 40 + R_SPARC_WDISP19 R_SPARC = 41 + R_SPARC_GLOB_JMP R_SPARC = 42 + R_SPARC_7 R_SPARC = 43 + R_SPARC_5 R_SPARC = 44 + R_SPARC_6 R_SPARC = 45 + R_SPARC_DISP64 R_SPARC = 46 + R_SPARC_PLT64 R_SPARC = 47 + R_SPARC_HIX22 R_SPARC = 48 + R_SPARC_LOX10 R_SPARC = 49 + R_SPARC_H44 R_SPARC = 50 + R_SPARC_M44 R_SPARC = 51 + R_SPARC_L44 R_SPARC = 52 + R_SPARC_REGISTER R_SPARC = 53 + R_SPARC_UA64 R_SPARC = 54 + R_SPARC_UA16 R_SPARC = 55 +) + +var rsparcStrings = []intName{ + {0, "R_SPARC_NONE"}, + {1, "R_SPARC_8"}, + {2, "R_SPARC_16"}, + {3, "R_SPARC_32"}, + {4, "R_SPARC_DISP8"}, + {5, "R_SPARC_DISP16"}, + {6, "R_SPARC_DISP32"}, + {7, "R_SPARC_WDISP30"}, + {8, "R_SPARC_WDISP22"}, + {9, "R_SPARC_HI22"}, + {10, "R_SPARC_22"}, + {11, "R_SPARC_13"}, + {12, "R_SPARC_LO10"}, + {13, "R_SPARC_GOT10"}, + {14, "R_SPARC_GOT13"}, + {15, "R_SPARC_GOT22"}, + {16, "R_SPARC_PC10"}, + {17, "R_SPARC_PC22"}, + {18, "R_SPARC_WPLT30"}, + {19, "R_SPARC_COPY"}, + {20, "R_SPARC_GLOB_DAT"}, + {21, "R_SPARC_JMP_SLOT"}, + {22, "R_SPARC_RELATIVE"}, + {23, "R_SPARC_UA32"}, + {24, "R_SPARC_PLT32"}, + {25, "R_SPARC_HIPLT22"}, + {26, "R_SPARC_LOPLT10"}, + {27, "R_SPARC_PCPLT32"}, + {28, "R_SPARC_PCPLT22"}, + {29, "R_SPARC_PCPLT10"}, + {30, "R_SPARC_10"}, + {31, "R_SPARC_11"}, + {32, "R_SPARC_64"}, + {33, "R_SPARC_OLO10"}, + {34, "R_SPARC_HH22"}, + {35, "R_SPARC_HM10"}, + {36, "R_SPARC_LM22"}, + {37, "R_SPARC_PC_HH22"}, + {38, "R_SPARC_PC_HM10"}, + {39, "R_SPARC_PC_LM22"}, + {40, "R_SPARC_WDISP16"}, + {41, "R_SPARC_WDISP19"}, + {42, "R_SPARC_GLOB_JMP"}, + {43, "R_SPARC_7"}, + {44, "R_SPARC_5"}, + {45, "R_SPARC_6"}, + {46, "R_SPARC_DISP64"}, + {47, "R_SPARC_PLT64"}, + {48, "R_SPARC_HIX22"}, + {49, "R_SPARC_LOX10"}, + {50, "R_SPARC_H44"}, + {51, "R_SPARC_M44"}, + {52, "R_SPARC_L44"}, + {53, "R_SPARC_REGISTER"}, + {54, "R_SPARC_UA64"}, + {55, "R_SPARC_UA16"}, +} + +func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) } +func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) } + +// Magic number for the elf trampoline, chosen wisely to be an immediate value. +const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003 + +// ELF32 File header. +type Header32 struct { + Ident [EI_NIDENT]byte /* File identification. */ + Type uint16 /* File type. */ + Machine uint16 /* Machine architecture. */ + Version uint32 /* ELF format version. */ + Entry uint32 /* Entry point. */ + Phoff uint32 /* Program header file offset. */ + Shoff uint32 /* Section header file offset. */ + Flags uint32 /* Architecture-specific flags. */ + Ehsize uint16 /* Size of ELF header in bytes. */ + Phentsize uint16 /* Size of program header entry. */ + Phnum uint16 /* Number of program header entries. */ + Shentsize uint16 /* Size of section header entry. */ + Shnum uint16 /* Number of section header entries. */ + Shstrndx uint16 /* Section name strings section. */ +} + +// ELF32 Section header. +type Section32 struct { + Name uint32 /* Section name (index into the section header string table). */ + Type uint32 /* Section type. */ + Flags uint32 /* Section flags. */ + Addr uint32 /* Address in memory image. */ + Off uint32 /* Offset in file. */ + Size uint32 /* Size in bytes. */ + Link uint32 /* Index of a related section. */ + Info uint32 /* Depends on section type. */ + Addralign uint32 /* Alignment in bytes. */ + Entsize uint32 /* Size of each entry in section. */ +} + +// ELF32 Program header. +type Prog32 struct { + Type uint32 /* Entry type. */ + Off uint32 /* File offset of contents. */ + Vaddr uint32 /* Virtual address in memory image. */ + Paddr uint32 /* Physical address (not used). */ + Filesz uint32 /* Size of contents in file. */ + Memsz uint32 /* Size of contents in memory. */ + Flags uint32 /* Access permission flags. */ + Align uint32 /* Alignment in memory and file. */ +} + +// ELF32 Dynamic structure. The ".dynamic" section contains an array of them. +type Dyn32 struct { + Tag int32 /* Entry type. */ + Val uint32 /* Integer/Address value. */ +} + +/* + * Relocation entries. + */ + +// ELF32 Relocations that don't need an addend field. +type Rel32 struct { + Off uint32 /* Location to be relocated. */ + Info uint32 /* Relocation type and symbol index. */ +} + +// ELF32 Relocations that need an addend field. +type Rela32 struct { + Off uint32 /* Location to be relocated. */ + Info uint32 /* Relocation type and symbol index. */ + Addend int32 /* Addend. */ +} + +func R_SYM32(info uint32) uint32 { return uint32(info >> 8) } +func R_TYPE32(info uint32) uint32 { return uint32(info & 0xff) } +func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ } + +// ELF32 Symbol. +type Sym32 struct { + Name uint32 + Value uint32 + Size uint32 + Info uint8 + Other uint8 + Shndx uint16 +} + +const Sym32Size = 16 + +func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) } +func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) } +func ST_INFO(bind SymBind, typ SymType) uint8 { + return uint8(bind)<<4 | uint8(typ)&0xf +} +func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) } + +/* + * ELF64 + */ + +// ELF64 file header. +type Header64 struct { + Ident [EI_NIDENT]byte /* File identification. */ + Type uint16 /* File type. */ + Machine uint16 /* Machine architecture. */ + Version uint32 /* ELF format version. */ + Entry uint64 /* Entry point. */ + Phoff uint64 /* Program header file offset. */ + Shoff uint64 /* Section header file offset. */ + Flags uint32 /* Architecture-specific flags. */ + Ehsize uint16 /* Size of ELF header in bytes. */ + Phentsize uint16 /* Size of program header entry. */ + Phnum uint16 /* Number of program header entries. */ + Shentsize uint16 /* Size of section header entry. */ + Shnum uint16 /* Number of section header entries. */ + Shstrndx uint16 /* Section name strings section. */ +} + +// ELF64 Section header. +type Section64 struct { + Name uint32 /* Section name (index into the section header string table). */ + Type uint32 /* Section type. */ + Flags uint64 /* Section flags. */ + Addr uint64 /* Address in memory image. */ + Off uint64 /* Offset in file. */ + Size uint64 /* Size in bytes. */ + Link uint32 /* Index of a related section. */ + Info uint32 /* Depends on section type. */ + Addralign uint64 /* Alignment in bytes. */ + Entsize uint64 /* Size of each entry in section. */ +} + +// ELF64 Program header. +type Prog64 struct { + Type uint32 /* Entry type. */ + Flags uint32 /* Access permission flags. */ + Off uint64 /* File offset of contents. */ + Vaddr uint64 /* Virtual address in memory image. */ + Paddr uint64 /* Physical address (not used). */ + Filesz uint64 /* Size of contents in file. */ + Memsz uint64 /* Size of contents in memory. */ + Align uint64 /* Alignment in memory and file. */ +} + +// ELF64 Dynamic structure. The ".dynamic" section contains an array of them. +type Dyn64 struct { + Tag int64 /* Entry type. */ + Val uint64 /* Integer/address value */ +} + +/* + * Relocation entries. + */ + +/* ELF64 relocations that don't need an addend field. */ +type Rel64 struct { + Off uint64 /* Location to be relocated. */ + Info uint64 /* Relocation type and symbol index. */ +} + +/* ELF64 relocations that need an addend field. */ +type Rela64 struct { + Off uint64 /* Location to be relocated. */ + Info uint64 /* Relocation type and symbol index. */ + Addend int64 /* Addend. */ +} + +func R_SYM64(info uint64) uint32 { return uint32(info >> 32) } +func R_TYPE64(info uint64) uint32 { return uint32(info) } +func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) } + +// ELF64 symbol table entries. +type Sym64 struct { + Name uint32 /* String table index of name. */ + Info uint8 /* Type and binding information. */ + Other uint8 /* Reserved (not used). */ + Shndx uint16 /* Section index of symbol. */ + Value uint64 /* Symbol value. */ + Size uint64 /* Size of associated object. */ +} + +const Sym64Size = 24 + +type intName struct { + i uint32 + s string +} + +func stringName(i uint32, names []intName, goSyntax bool) string { + for _, n := range names { + if n.i == i { + if goSyntax { + return "elf." + n.s + } + return n.s + } + } + + // second pass - look for smaller to add with. + // assume sorted already + for j := len(names) - 1; j >= 0; j-- { + n := names[j] + if n.i < i { + s := n.s + if goSyntax { + s = "elf." + s + } + return s + "+" + strconv.FormatUint(uint64(i-n.i), 10) + } + } + + return strconv.FormatUint(uint64(i), 10) +} + +func flagName(i uint32, names []intName, goSyntax bool) string { + s := "" + for _, n := range names { + if n.i&i == n.i { + if len(s) > 0 { + s += "+" + } + if goSyntax { + s += "elf." + } + s += n.s + i -= n.i + } + } + if len(s) == 0 { + return "0x" + strconv.FormatUint(uint64(i), 16) + } + if i != 0 { + s += "+0x" + strconv.FormatUint(uint64(i), 16) + } + return s +} diff --git a/vendor/golang.org/x/debug/elf/file.go b/vendor/golang.org/x/debug/elf/file.go new file mode 100644 index 0000000..6946550 --- /dev/null +++ b/vendor/golang.org/x/debug/elf/file.go @@ -0,0 +1,829 @@ +// 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 elf implements access to ELF object files. +package elf + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "os" + + "golang.org/x/debug/dwarf" +) + +// TODO: error reporting detail + +/* + * Internal ELF representation + */ + +// A FileHeader represents an ELF file header. +type FileHeader struct { + Class Class + Data Data + Version Version + OSABI OSABI + ABIVersion uint8 + ByteOrder binary.ByteOrder + Type Type + Machine Machine + Entry uint64 +} + +// A File represents an open ELF file. +type File struct { + FileHeader + Sections []*Section + Progs []*Prog + closer io.Closer + gnuNeed []verneed + gnuVersym []byte +} + +// A SectionHeader represents a single ELF section header. +type SectionHeader struct { + Name string + Type SectionType + Flags SectionFlag + Addr uint64 + Offset uint64 + Size uint64 + Link uint32 + Info uint32 + Addralign uint64 + Entsize uint64 +} + +// A Section represents a single section in an ELF 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 ELF 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 +} + +// stringTable reads and returns the string table given by the +// specified link value. +func (f *File) stringTable(link uint32) ([]byte, error) { + if link <= 0 || link >= uint32(len(f.Sections)) { + return nil, errors.New("section has invalid string table link") + } + return f.Sections[link].Data() +} + +// Open returns a new ReadSeeker reading the ELF section. +func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } + +// A ProgHeader represents a single ELF program header. +type ProgHeader struct { + Type ProgType + Flags ProgFlag + Off uint64 + Vaddr uint64 + Paddr uint64 + Filesz uint64 + Memsz uint64 + Align uint64 +} + +// A Prog represents a single ELF program header in an ELF binary. +type Prog struct { + ProgHeader + + // 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 +} + +// Open returns a new ReadSeeker reading the ELF program body. +func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } + +// A Symbol represents an entry in an ELF symbol table section. +type Symbol struct { + Name string + Info, Other byte + Section SectionIndex + Value, Size uint64 +} + +/* + * ELF reader + */ + +type FormatError struct { + off int64 + 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 an ELF 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 +} + +// SectionByType returns the first section in f with the +// given type, or nil if there is no such section. +func (f *File) SectionByType(typ SectionType) *Section { + for _, s := range f.Sections { + if s.Type == typ { + return s + } + } + return nil +} + +// NewFile creates a new File for accessing an ELF binary in an underlying reader. +// The ELF 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 ELF identifier + var ident [16]uint8 + if _, err := r.ReadAt(ident[0:], 0); err != nil { + return nil, err + } + if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { + return nil, &FormatError{0, "bad magic number", ident[0:4]} + } + + f := new(File) + f.Class = Class(ident[EI_CLASS]) + switch f.Class { + case ELFCLASS32: + case ELFCLASS64: + // ok + default: + return nil, &FormatError{0, "unknown ELF class", f.Class} + } + + f.Data = Data(ident[EI_DATA]) + switch f.Data { + case ELFDATA2LSB: + f.ByteOrder = binary.LittleEndian + case ELFDATA2MSB: + f.ByteOrder = binary.BigEndian + default: + return nil, &FormatError{0, "unknown ELF data encoding", f.Data} + } + + f.Version = Version(ident[EI_VERSION]) + if f.Version != EV_CURRENT { + return nil, &FormatError{0, "unknown ELF version", f.Version} + } + + f.OSABI = OSABI(ident[EI_OSABI]) + f.ABIVersion = ident[EI_ABIVERSION] + + // Read ELF file header + var phoff int64 + var phentsize, phnum int + var shoff int64 + var shentsize, shnum, shstrndx int + shstrndx = -1 + switch f.Class { + case ELFCLASS32: + hdr := new(Header32) + sr.Seek(0, os.SEEK_SET) + if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { + return nil, err + } + f.Type = Type(hdr.Type) + f.Machine = Machine(hdr.Machine) + f.Entry = uint64(hdr.Entry) + if v := Version(hdr.Version); v != f.Version { + return nil, &FormatError{0, "mismatched ELF version", v} + } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) + shoff = int64(hdr.Shoff) + shentsize = int(hdr.Shentsize) + shnum = int(hdr.Shnum) + shstrndx = int(hdr.Shstrndx) + case ELFCLASS64: + hdr := new(Header64) + sr.Seek(0, os.SEEK_SET) + if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { + return nil, err + } + f.Type = Type(hdr.Type) + f.Machine = Machine(hdr.Machine) + f.Entry = uint64(hdr.Entry) + if v := Version(hdr.Version); v != f.Version { + return nil, &FormatError{0, "mismatched ELF version", v} + } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) + shoff = int64(hdr.Shoff) + shentsize = int(hdr.Shentsize) + shnum = int(hdr.Shnum) + shstrndx = int(hdr.Shstrndx) + } + + if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { + return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} + } + + // Read program headers + f.Progs = make([]*Prog, phnum) + for i := 0; i < phnum; i++ { + off := phoff + int64(i)*int64(phentsize) + sr.Seek(off, os.SEEK_SET) + p := new(Prog) + switch f.Class { + case ELFCLASS32: + ph := new(Prog32) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: uint64(ph.Off), + Vaddr: uint64(ph.Vaddr), + Paddr: uint64(ph.Paddr), + Filesz: uint64(ph.Filesz), + Memsz: uint64(ph.Memsz), + Align: uint64(ph.Align), + } + case ELFCLASS64: + ph := new(Prog64) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: uint64(ph.Off), + Vaddr: uint64(ph.Vaddr), + Paddr: uint64(ph.Paddr), + Filesz: uint64(ph.Filesz), + Memsz: uint64(ph.Memsz), + Align: uint64(ph.Align), + } + } + p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) + p.ReaderAt = p.sr + f.Progs[i] = p + } + + // Read section headers + f.Sections = make([]*Section, shnum) + names := make([]uint32, shnum) + for i := 0; i < shnum; i++ { + off := shoff + int64(i)*int64(shentsize) + sr.Seek(off, os.SEEK_SET) + s := new(Section) + switch f.Class { + case ELFCLASS32: + sh := new(Section32) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + names[i] = sh.Name + s.SectionHeader = SectionHeader{ + Type: SectionType(sh.Type), + Flags: SectionFlag(sh.Flags), + Addr: uint64(sh.Addr), + Offset: uint64(sh.Off), + Size: uint64(sh.Size), + Link: uint32(sh.Link), + Info: uint32(sh.Info), + Addralign: uint64(sh.Addralign), + Entsize: uint64(sh.Entsize), + } + case ELFCLASS64: + sh := new(Section64) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + names[i] = sh.Name + s.SectionHeader = SectionHeader{ + Type: SectionType(sh.Type), + Flags: SectionFlag(sh.Flags), + Offset: uint64(sh.Off), + Size: uint64(sh.Size), + Addr: uint64(sh.Addr), + Link: uint32(sh.Link), + Info: uint32(sh.Info), + Addralign: uint64(sh.Addralign), + Entsize: uint64(sh.Entsize), + } + } + s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size)) + s.ReaderAt = s.sr + f.Sections[i] = s + } + + if len(f.Sections) == 0 { + return f, nil + } + + // Load section header string table. + shstrtab, err := f.Sections[shstrndx].Data() + if err != nil { + return nil, err + } + for i, s := range f.Sections { + var ok bool + s.Name, ok = getString(shstrtab, int(names[i])) + if !ok { + return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} + } + } + + return f, nil +} + +// getSymbols returns a slice of Symbols from parsing the symbol table +// with the given type, along with the associated string table. +func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { + switch f.Class { + case ELFCLASS64: + return f.getSymbols64(typ) + + case ELFCLASS32: + return f.getSymbols32(typ) + } + + return nil, nil, errors.New("not implemented") +} + +func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { + symtabSection := f.SectionByType(typ) + if symtabSection == nil { + return nil, nil, errors.New("no symbol section") + } + + data, err := symtabSection.Data() + if err != nil { + return nil, nil, errors.New("cannot load symbol section") + } + symtab := bytes.NewReader(data) + if symtab.Len()%Sym32Size != 0 { + return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") + } + + strdata, err := f.stringTable(symtabSection.Link) + if err != nil { + return nil, nil, errors.New("cannot load string table section") + } + + // The first entry is all zeros. + var skip [Sym32Size]byte + symtab.Read(skip[:]) + + symbols := make([]Symbol, symtab.Len()/Sym32Size) + + i := 0 + var sym Sym32 + for symtab.Len() > 0 { + binary.Read(symtab, f.ByteOrder, &sym) + str, _ := getString(strdata, int(sym.Name)) + symbols[i].Name = str + symbols[i].Info = sym.Info + symbols[i].Other = sym.Other + symbols[i].Section = SectionIndex(sym.Shndx) + symbols[i].Value = uint64(sym.Value) + symbols[i].Size = uint64(sym.Size) + i++ + } + + return symbols, strdata, nil +} + +func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { + symtabSection := f.SectionByType(typ) + if symtabSection == nil { + return nil, nil, errors.New("no symbol section") + } + + data, err := symtabSection.Data() + if err != nil { + return nil, nil, errors.New("cannot load symbol section") + } + symtab := bytes.NewReader(data) + if symtab.Len()%Sym64Size != 0 { + return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") + } + + strdata, err := f.stringTable(symtabSection.Link) + if err != nil { + return nil, nil, errors.New("cannot load string table section") + } + + // The first entry is all zeros. + var skip [Sym64Size]byte + symtab.Read(skip[:]) + + symbols := make([]Symbol, symtab.Len()/Sym64Size) + + i := 0 + var sym Sym64 + for symtab.Len() > 0 { + binary.Read(symtab, f.ByteOrder, &sym) + str, _ := getString(strdata, int(sym.Name)) + symbols[i].Name = str + symbols[i].Info = sym.Info + symbols[i].Other = sym.Other + symbols[i].Section = SectionIndex(sym.Shndx) + symbols[i].Value = sym.Value + symbols[i].Size = sym.Size + i++ + } + + return symbols, strdata, nil +} + +// getString extracts a string from an ELF string table. +func getString(section []byte, start int) (string, bool) { + if start < 0 || start >= len(section) { + return "", false + } + + for end := start; end < len(section); end++ { + if section[end] == 0 { + return string(section[start:end]), true + } + } + return "", false +} + +// 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 +} + +// applyRelocations applies relocations to dst. rels is a relocations section +// in RELA format. +func (f *File) applyRelocations(dst []byte, rels []byte) error { + if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { + return f.applyRelocationsAMD64(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") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_X86_64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + switch t { + case R_X86_64_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_X86_64_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + 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 + // does not use the others, so don't bother loading them. + // r: added line. + var names = [...]string{"abbrev", "frame", "info", "line", "str"} + var dat [len(names)][]byte + for i, name := range names { + name = ".debug_" + name + s := f.Section(name) + if s == nil { + continue + } + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + return nil, err + } + dat[i] = b + } + + // If there's a relocation table for .debug_info, we have to process it + // now otherwise the data in .debug_info is invalid for x86-64 objects. + rela := f.Section(".rela.debug_info") + if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 { + data, err := rela.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(dat[2], data) + if err != nil { + return nil, err + } + } + + abbrev, frame, info, line, str := dat[0], dat[1], dat[2], dat[3], dat[4] + d, err := dwarf.New(abbrev, nil, frame, info, line, 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. +// +// For compatibility with Go 1.0, Symbols omits the null symbol at index 0. +// After retrieving the symbols as symtab, an externally supplied index x +// corresponds to symtab[x-1], not symtab[x]. +func (f *File) Symbols() ([]Symbol, error) { + sym, _, err := f.getSymbols(SHT_SYMTAB) + return sym, err +} + +type ImportedSymbol struct { + Name string + Version string + Library string +} + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +// It does not return weak symbols. +func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { + sym, str, err := f.getSymbols(SHT_DYNSYM) + if err != nil { + return nil, err + } + f.gnuVersionInit(str) + var all []ImportedSymbol + for i, s := range sym { + if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { + all = append(all, ImportedSymbol{Name: s.Name}) + f.gnuVersion(i, &all[len(all)-1]) + } + } + return all, nil +} + +type verneed struct { + File string + Name string +} + +// gnuVersionInit parses the GNU version tables +// for use by calls to gnuVersion. +func (f *File) gnuVersionInit(str []byte) { + // Accumulate verneed information. + vn := f.SectionByType(SHT_GNU_VERNEED) + if vn == nil { + return + } + d, _ := vn.Data() + + var need []verneed + i := 0 + for { + if i+16 > len(d) { + break + } + vers := f.ByteOrder.Uint16(d[i : i+2]) + if vers != 1 { + break + } + cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) + fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) + aux := f.ByteOrder.Uint32(d[i+8 : i+12]) + next := f.ByteOrder.Uint32(d[i+12 : i+16]) + file, _ := getString(str, int(fileoff)) + + var name string + j := i + int(aux) + for c := 0; c < int(cnt); c++ { + if j+16 > len(d) { + break + } + // hash := f.ByteOrder.Uint32(d[j:j+4]) + // flags := f.ByteOrder.Uint16(d[j+4:j+6]) + other := f.ByteOrder.Uint16(d[j+6 : j+8]) + nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) + next := f.ByteOrder.Uint32(d[j+12 : j+16]) + name, _ = getString(str, int(nameoff)) + ndx := int(other) + if ndx >= len(need) { + a := make([]verneed, 2*(ndx+1)) + copy(a, need) + need = a + } + + need[ndx] = verneed{file, name} + if next == 0 { + break + } + j += int(next) + } + + if next == 0 { + break + } + i += int(next) + } + + // Versym parallels symbol table, indexing into verneed. + vs := f.SectionByType(SHT_GNU_VERSYM) + if vs == nil { + return + } + d, _ = vs.Data() + + f.gnuNeed = need + f.gnuVersym = d +} + +// gnuVersion adds Library and Version information to sym, +// which came from offset i of the symbol table. +func (f *File) gnuVersion(i int, sym *ImportedSymbol) { + // Each entry is two bytes. + i = (i + 1) * 2 + if i >= len(f.gnuVersym) { + return + } + j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) + if j < 2 || j >= len(f.gnuNeed) { + return + } + n := &f.gnuNeed[j] + sym.Library = n.File + sym.Version = n.Name +} + +// ImportedLibraries returns the names of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, error) { + return f.DynString(DT_NEEDED) +} + +// DynString returns the strings listed for the given tag in the file's dynamic +// section. +// +// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or +// DT_RUNPATH. +func (f *File) DynString(tag DynTag) ([]string, error) { + switch tag { + case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: + default: + return nil, fmt.Errorf("non-string-valued tag %v", tag) + } + ds := f.SectionByType(SHT_DYNAMIC) + if ds == nil { + // not dynamic, so no libraries + return nil, nil + } + d, err := ds.Data() + if err != nil { + return nil, err + } + str, err := f.stringTable(ds.Link) + if err != nil { + return nil, err + } + var all []string + for len(d) > 0 { + var t DynTag + var v uint64 + switch f.Class { + case ELFCLASS32: + t = DynTag(f.ByteOrder.Uint32(d[0:4])) + v = uint64(f.ByteOrder.Uint32(d[4:8])) + d = d[8:] + case ELFCLASS64: + t = DynTag(f.ByteOrder.Uint64(d[0:8])) + v = f.ByteOrder.Uint64(d[8:16]) + d = d[16:] + } + if t == tag { + s, ok := getString(str, int(v)) + if ok { + all = append(all, s) + } + } + } + return all, nil +} diff --git a/vendor/golang.org/x/debug/macho/fat.go b/vendor/golang.org/x/debug/macho/fat.go new file mode 100644 index 0000000..93b8315 --- /dev/null +++ b/vendor/golang.org/x/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/vendor/golang.org/x/debug/macho/file.go b/vendor/golang.org/x/debug/macho/file.go new file mode 100644 index 0000000..7f59901 --- /dev/null +++ b/vendor/golang.org/x/debug/macho/file.go @@ -0,0 +1,525 @@ +// 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 macho implements access to Mach-O object files. +package macho + +// High level access to low level data structures. + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "os" + + "golang.org/x/debug/dwarf" +) + +// A File represents an open Mach-O file. +type File struct { + FileHeader + ByteOrder binary.ByteOrder + Loads []Load + Sections []*Section + + Symtab *Symtab + Dysymtab *Dysymtab + + closer io.Closer +} + +// A Load represents any Mach-O load command. +type Load interface { + Raw() []byte +} + +// A LoadBytes is the uninterpreted bytes of a Mach-O load command. +type LoadBytes []byte + +func (b LoadBytes) Raw() []byte { return b } + +// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command. +type SegmentHeader struct { + Cmd LoadCmd + Len uint32 + Name string + Addr uint64 + Memsz uint64 + Offset uint64 + Filesz uint64 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 +} + +// A Segment represents a Mach-O 32-bit or 64-bit load segment command. +type Segment struct { + LoadBytes + SegmentHeader + + // 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 segment. +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 +} + +// Open returns a new ReadSeeker reading the segment. +func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } + +type SectionHeader struct { + Name string + Seg string + Addr uint64 + Size uint64 + Offset uint32 + Align uint32 + Reloff uint32 + Nreloc uint32 + Flags uint32 +} + +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 Mach-O 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 Mach-O section. +func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } + +// A Dylib represents a Mach-O load dynamic library command. +type Dylib struct { + LoadBytes + Name string + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 +} + +// A Symtab represents a Mach-O symbol table command. +type Symtab struct { + LoadBytes + SymtabCmd + Syms []Symbol +} + +// A Dysymtab represents a Mach-O dynamic symbol table command. +type Dysymtab struct { + LoadBytes + DysymtabCmd + IndirectSyms []uint32 // indices into Symtab.Syms +} + +/* + * Mach-O reader + */ + +// FormatError is returned by some operations if the data does +// not have the correct format for an object file. +type FormatError struct { + off int64 + 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 Mach-O 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 +} + +// NewFile creates a new File for accessing a Mach-O binary in an underlying reader. +// The Mach-O binary is expected to start at position 0 in the ReaderAt. +func NewFile(r io.ReaderAt) (*File, error) { + f := new(File) + sr := io.NewSectionReader(r, 0, 1<<63-1) + + // Read and decode Mach magic to determine byte order, size. + // Magic32 and Magic64 differ only in the bottom bit. + var ident [4]byte + if _, err := r.ReadAt(ident[0:], 0); err != nil { + return nil, err + } + be := binary.BigEndian.Uint32(ident[0:]) + le := binary.LittleEndian.Uint32(ident[0:]) + switch Magic32 &^ 1 { + case be &^ 1: + f.ByteOrder = binary.BigEndian + f.Magic = be + case le &^ 1: + f.ByteOrder = binary.LittleEndian + f.Magic = le + default: + return nil, &FormatError{0, "invalid magic number", nil} + } + + // Read entire file header. + if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil { + return nil, err + } + + // Then load commands. + offset := int64(fileHeaderSize32) + if f.Magic == Magic64 { + offset = fileHeaderSize64 + } + dat := make([]byte, f.Cmdsz) + if _, err := r.ReadAt(dat, offset); err != nil { + return nil, err + } + f.Loads = make([]Load, f.Ncmd) + bo := f.ByteOrder + for i := range f.Loads { + // Each load command begins with uint32 command and length. + if len(dat) < 8 { + return nil, &FormatError{offset, "command block too small", nil} + } + cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8]) + if siz < 8 || siz > uint32(len(dat)) { + return nil, &FormatError{offset, "invalid command block size", nil} + } + var cmddat []byte + cmddat, dat = dat[0:siz], dat[siz:] + offset += int64(siz) + var s *Segment + switch cmd { + default: + f.Loads[i] = LoadBytes(cmddat) + + case LoadCmdDylib: + var hdr DylibCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + l := new(Dylib) + if hdr.Name >= uint32(len(cmddat)) { + return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name} + } + l.Name = cstring(cmddat[hdr.Name:]) + l.Time = hdr.Time + l.CurrentVersion = hdr.CurrentVersion + l.CompatVersion = hdr.CompatVersion + l.LoadBytes = LoadBytes(cmddat) + f.Loads[i] = l + + case LoadCmdSymtab: + var hdr SymtabCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + strtab := make([]byte, hdr.Strsize) + if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil { + return nil, err + } + var symsz int + if f.Magic == Magic64 { + symsz = 16 + } else { + symsz = 12 + } + symdat := make([]byte, int(hdr.Nsyms)*symsz) + if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil { + return nil, err + } + st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset) + if err != nil { + return nil, err + } + f.Loads[i] = st + f.Symtab = st + + case LoadCmdDysymtab: + var hdr DysymtabCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + dat := make([]byte, hdr.Nindirectsyms*4) + if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil { + return nil, err + } + x := make([]uint32, hdr.Nindirectsyms) + if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil { + return nil, err + } + st := new(Dysymtab) + st.LoadBytes = LoadBytes(cmddat) + st.DysymtabCmd = hdr + st.IndirectSyms = x + f.Loads[i] = st + f.Dysymtab = st + + case LoadCmdSegment: + var seg32 Segment32 + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &seg32); err != nil { + return nil, err + } + s = new(Segment) + s.LoadBytes = cmddat + s.Cmd = cmd + s.Len = siz + s.Name = cstring(seg32.Name[0:]) + s.Addr = uint64(seg32.Addr) + s.Memsz = uint64(seg32.Memsz) + s.Offset = uint64(seg32.Offset) + s.Filesz = uint64(seg32.Filesz) + s.Maxprot = seg32.Maxprot + s.Prot = seg32.Prot + s.Nsect = seg32.Nsect + s.Flag = seg32.Flag + f.Loads[i] = s + for i := 0; i < int(s.Nsect); i++ { + var sh32 Section32 + if err := binary.Read(b, bo, &sh32); err != nil { + return nil, err + } + sh := new(Section) + sh.Name = cstring(sh32.Name[0:]) + sh.Seg = cstring(sh32.Seg[0:]) + sh.Addr = uint64(sh32.Addr) + sh.Size = uint64(sh32.Size) + sh.Offset = sh32.Offset + sh.Align = sh32.Align + sh.Reloff = sh32.Reloff + sh.Nreloc = sh32.Nreloc + sh.Flags = sh32.Flags + f.pushSection(sh, r) + } + + case LoadCmdSegment64: + var seg64 Segment64 + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &seg64); err != nil { + return nil, err + } + s = new(Segment) + s.LoadBytes = cmddat + s.Cmd = cmd + s.Len = siz + s.Name = cstring(seg64.Name[0:]) + s.Addr = seg64.Addr + s.Memsz = seg64.Memsz + s.Offset = seg64.Offset + s.Filesz = seg64.Filesz + s.Maxprot = seg64.Maxprot + s.Prot = seg64.Prot + s.Nsect = seg64.Nsect + s.Flag = seg64.Flag + f.Loads[i] = s + for i := 0; i < int(s.Nsect); i++ { + var sh64 Section64 + if err := binary.Read(b, bo, &sh64); err != nil { + return nil, err + } + sh := new(Section) + sh.Name = cstring(sh64.Name[0:]) + sh.Seg = cstring(sh64.Seg[0:]) + sh.Addr = sh64.Addr + sh.Size = sh64.Size + sh.Offset = sh64.Offset + sh.Align = sh64.Align + sh.Reloff = sh64.Reloff + sh.Nreloc = sh64.Nreloc + sh.Flags = sh64.Flags + f.pushSection(sh, r) + } + } + if s != nil { + s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz)) + s.ReaderAt = s.sr + } + } + return f, nil +} + +func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) { + bo := f.ByteOrder + symtab := make([]Symbol, hdr.Nsyms) + b := bytes.NewReader(symdat) + for i := range symtab { + var n Nlist64 + if f.Magic == Magic64 { + if err := binary.Read(b, bo, &n); err != nil { + return nil, err + } + } else { + var n32 Nlist32 + if err := binary.Read(b, bo, &n32); err != nil { + return nil, err + } + n.Name = n32.Name + n.Type = n32.Type + n.Sect = n32.Sect + n.Desc = n32.Desc + n.Value = uint64(n32.Value) + } + sym := &symtab[i] + if n.Name >= uint32(len(strtab)) { + return nil, &FormatError{offset, "invalid name in symbol table", n.Name} + } + sym.Name = cstring(strtab[n.Name:]) + sym.Type = n.Type + sym.Sect = n.Sect + sym.Desc = n.Desc + sym.Value = n.Value + } + st := new(Symtab) + st.LoadBytes = LoadBytes(cmddat) + st.Syms = symtab + return st, nil +} + +func (f *File) pushSection(sh *Section, r io.ReaderAt) { + f.Sections = append(f.Sections, sh) + sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size)) + sh.ReaderAt = sh.sr +} + +func cstring(b []byte) string { + var i int + for i = 0; i < len(b) && b[i] != 0; i++ { + } + return string(b[0:i]) +} + +// Segment returns the first Segment with the given name, or nil if no such segment exists. +func (f *File) Segment(name string) *Segment { + for _, l := range f.Loads { + if s, ok := l.(*Segment); ok && s.Name == name { + return s + } + } + return nil +} + +// Section returns the first 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 +} + +// DWARF returns the DWARF debug information for the Mach-O file. +func (f *File) DWARF() (*dwarf.Data, error) { + // There are many other DWARF sections, but these + // are the required ones, and the debug/dwarf package + // does not use the others, so don't bother loading them. + var names = [...]string{"abbrev", "frame", "info", "line", "str"} + var dat [len(names)][]byte + for i, name := range names { + name = "__debug_" + name + s := f.Section(name) + if s == nil { + continue + } + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + return nil, err + } + dat[i] = b + } + + abbrev, frame, info, line, str := dat[0], dat[1], dat[2], dat[3], dat[4] + return dwarf.New(abbrev, nil, frame, info, line, nil, nil, str) +} + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +func (f *File) ImportedSymbols() ([]string, error) { + if f.Dysymtab == nil || f.Symtab == nil { + return nil, &FormatError{0, "missing symbol table", nil} + } + + st := f.Symtab + dt := f.Dysymtab + var all []string + for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] { + all = append(all, s.Name) + } + return all, nil +} + +// ImportedLibraries returns the paths of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, error) { + var all []string + for _, l := range f.Loads { + if lib, ok := l.(*Dylib); ok { + all = append(all, lib.Name) + } + } + return all, nil +} diff --git a/vendor/golang.org/x/debug/macho/macho.go b/vendor/golang.org/x/debug/macho/macho.go new file mode 100644 index 0000000..d9678c8 --- /dev/null +++ b/vendor/golang.org/x/debug/macho/macho.go @@ -0,0 +1,316 @@ +// 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. + +// Mach-O header data structures +// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html + +package macho + +import "strconv" + +// A FileHeader represents a Mach-O file header. +type FileHeader struct { + Magic uint32 + Cpu Cpu + SubCpu uint32 + Type Type + Ncmd uint32 + Cmdsz uint32 + Flags uint32 +} + +const ( + fileHeaderSize32 = 7 * 4 + fileHeaderSize64 = 8 * 4 +) + +const ( + Magic32 uint32 = 0xfeedface + Magic64 uint32 = 0xfeedfacf + MagicFat uint32 = 0xcafebabe +) + +// 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 + 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 | 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) } +func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) } + +// A LoadCmd is a Mach-O load command. +type LoadCmd uint32 + +const ( + LoadCmdSegment LoadCmd = 1 + LoadCmdSymtab LoadCmd = 2 + LoadCmdThread LoadCmd = 4 + LoadCmdUnixThread LoadCmd = 5 // thread+stack + LoadCmdDysymtab LoadCmd = 11 + LoadCmdDylib LoadCmd = 12 + LoadCmdDylinker LoadCmd = 15 + LoadCmdSegment64 LoadCmd = 25 +) + +var cmdStrings = []intName{ + {uint32(LoadCmdSegment), "LoadCmdSegment"}, + {uint32(LoadCmdThread), "LoadCmdThread"}, + {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"}, + {uint32(LoadCmdDylib), "LoadCmdDylib"}, + {uint32(LoadCmdSegment64), "LoadCmdSegment64"}, +} + +func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) } +func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) } + +// A Segment64 is a 64-bit Mach-O segment load command. +type Segment64 struct { + Cmd LoadCmd + Len uint32 + Name [16]byte + Addr uint64 + Memsz uint64 + Offset uint64 + Filesz uint64 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 +} + +// A Segment32 is a 32-bit Mach-O segment load command. +type Segment32 struct { + Cmd LoadCmd + Len uint32 + Name [16]byte + Addr uint32 + Memsz uint32 + Offset uint32 + Filesz uint32 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 +} + +// A DylibCmd is a Mach-O load dynamic library command. +type DylibCmd struct { + Cmd LoadCmd + Len uint32 + Name uint32 + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 +} + +// A Section32 is a 32-bit Mach-O section header. +type Section32 struct { + Name [16]byte + Seg [16]byte + Addr uint32 + Size uint32 + Offset uint32 + Align uint32 + Reloff uint32 + Nreloc uint32 + Flags uint32 + Reserve1 uint32 + Reserve2 uint32 +} + +// A Section32 is a 64-bit Mach-O section header. +type Section64 struct { + Name [16]byte + Seg [16]byte + Addr uint64 + Size uint64 + Offset uint32 + Align uint32 + Reloff uint32 + Nreloc uint32 + Flags uint32 + Reserve1 uint32 + Reserve2 uint32 + Reserve3 uint32 +} + +// A SymtabCmd is a Mach-O symbol table command. +type SymtabCmd struct { + Cmd LoadCmd + Len uint32 + Symoff uint32 + Nsyms uint32 + Stroff uint32 + Strsize uint32 +} + +// A DysymtabCmd is a Mach-O dynamic symbol table command. +type DysymtabCmd struct { + Cmd LoadCmd + Len uint32 + Ilocalsym uint32 + Nlocalsym uint32 + Iextdefsym uint32 + Nextdefsym uint32 + Iundefsym uint32 + Nundefsym uint32 + Tocoffset uint32 + Ntoc uint32 + Modtaboff uint32 + Nmodtab uint32 + Extrefsymoff uint32 + Nextrefsyms uint32 + Indirectsymoff uint32 + Nindirectsyms uint32 + Extreloff uint32 + Nextrel uint32 + Locreloff uint32 + Nlocrel uint32 +} + +// An Nlist32 is a Mach-O 32-bit symbol table entry. +type Nlist32 struct { + Name uint32 + Type uint8 + Sect uint8 + Desc uint16 + Value uint32 +} + +// An Nlist64 is a Mach-O 64-bit symbol table entry. +type Nlist64 struct { + Name uint32 + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + +// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. +type Symbol struct { + Name string + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + +// A Thread is a Mach-O thread state command. +type Thread struct { + Cmd LoadCmd + Len uint32 + Type uint32 + Data []uint32 +} + +// Regs386 is the Mach-O 386 register structure. +type Regs386 struct { + AX uint32 + BX uint32 + CX uint32 + DX uint32 + DI uint32 + SI uint32 + BP uint32 + SP uint32 + SS uint32 + FLAGS uint32 + IP uint32 + CS uint32 + DS uint32 + ES uint32 + FS uint32 + GS uint32 +} + +// RegsAMD64 is the Mach-O AMD64 register structure. +type RegsAMD64 struct { + AX uint64 + BX uint64 + CX uint64 + DX uint64 + DI uint64 + SI uint64 + BP uint64 + SP uint64 + R8 uint64 + R9 uint64 + R10 uint64 + R11 uint64 + R12 uint64 + R13 uint64 + R14 uint64 + R15 uint64 + IP uint64 + FLAGS uint64 + CS uint64 + FS uint64 + GS uint64 +} + +type intName struct { + i uint32 + s string +} + +func stringName(i uint32, names []intName, goSyntax bool) string { + for _, n := range names { + if n.i == i { + if goSyntax { + return "macho." + n.s + } + return n.s + } + } + return strconv.FormatUint(uint64(i), 10) +} + +func flagName(i uint32, names []intName, goSyntax bool) string { + s := "" + for _, n := range names { + if n.i&i == n.i { + if len(s) > 0 { + s += "+" + } + if goSyntax { + s += "macho." + } + s += n.s + i -= n.i + } + } + if len(s) == 0 { + return "0x" + strconv.FormatUint(uint64(i), 16) + } + if i != 0 { + s += "+0x" + strconv.FormatUint(uint64(i), 16) + } + return s +} diff --git a/vendor/golang.org/x/sys/windows/asm.s b/vendor/golang.org/x/sys/windows/asm.s new file mode 100644 index 0000000..d4ca868 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/asm.s @@ -0,0 +1,8 @@ +// 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 "textflag.h" + +TEXT ·use(SB),NOSPLIT,$0 + RET diff --git a/vendor/golang.org/x/sys/windows/asm_windows_386.s b/vendor/golang.org/x/sys/windows/asm_windows_386.s new file mode 100644 index 0000000..1c20dd2 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/asm_windows_386.s @@ -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. + +// +// System calls for 386, Windows are implemented in runtime/syscall_windows.goc +// + +TEXT ·getprocaddress(SB), 7, $0-8 + JMP syscall·getprocaddress(SB) + +TEXT ·loadlibrary(SB), 7, $0-4 + JMP syscall·loadlibrary(SB) diff --git a/vendor/golang.org/x/sys/windows/asm_windows_amd64.s b/vendor/golang.org/x/sys/windows/asm_windows_amd64.s new file mode 100644 index 0000000..4d025ab --- /dev/null +++ b/vendor/golang.org/x/sys/windows/asm_windows_amd64.s @@ -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. + +// +// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc +// + +TEXT ·getprocaddress(SB), 7, $0-32 + JMP syscall·getprocaddress(SB) + +TEXT ·loadlibrary(SB), 7, $0-8 + JMP syscall·loadlibrary(SB) diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go new file mode 100644 index 0000000..7f9f05f --- /dev/null +++ b/vendor/golang.org/x/sys/windows/dll_windows.go @@ -0,0 +1,275 @@ +// 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 windows + +import ( + "sync" + "sync/atomic" + "syscall" + "unsafe" +) + +// DLLError describes reasons for DLL load failures. +type DLLError struct { + Err error + ObjName string + Msg string +} + +func (e *DLLError) Error() string { return e.Msg } + +// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file. +func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno) +func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno) + +// A DLL implements access to a single DLL. +type DLL struct { + Name string + Handle Handle +} + +// LoadDLL loads DLL file into memory. +func LoadDLL(name string) (dll *DLL, err error) { + namep, err := UTF16PtrFromString(name) + if err != nil { + return nil, err + } + h, e := loadlibrary(namep) + if e != 0 { + return nil, &DLLError{ + Err: e, + ObjName: name, + Msg: "Failed to load " + name + ": " + e.Error(), + } + } + d := &DLL{ + Name: name, + Handle: Handle(h), + } + return d, nil +} + +// MustLoadDLL is like LoadDLL but panics if load operation failes. +func MustLoadDLL(name string) *DLL { + d, e := LoadDLL(name) + if e != nil { + panic(e) + } + return d +} + +// FindProc searches DLL d for procedure named name and returns *Proc +// if found. It returns an error if search fails. +func (d *DLL) FindProc(name string) (proc *Proc, err error) { + namep, err := BytePtrFromString(name) + if err != nil { + return nil, err + } + a, e := getprocaddress(uintptr(d.Handle), namep) + if e != 0 { + return nil, &DLLError{ + Err: e, + ObjName: name, + Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), + } + } + p := &Proc{ + Dll: d, + Name: name, + addr: a, + } + return p, nil +} + +// MustFindProc is like FindProc but panics if search fails. +func (d *DLL) MustFindProc(name string) *Proc { + p, e := d.FindProc(name) + if e != nil { + panic(e) + } + return p +} + +// Release unloads DLL d from memory. +func (d *DLL) Release() (err error) { + return FreeLibrary(d.Handle) +} + +// A Proc implements access to a procedure inside a DLL. +type Proc struct { + Dll *DLL + 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 15 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 windows.Errno. +func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { + switch len(a) { + case 0: + return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0) + case 1: + return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0) + case 2: + return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0) + case 3: + return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2]) + case 4: + return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) + case 5: + return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) + case 6: + return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) + case 7: + return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0) + case 8: + return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0) + case 9: + return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]) + case 10: + return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0) + case 11: + return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0) + case 12: + return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]) + case 13: + return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0) + case 14: + return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0) + case 15: + return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14]) + default: + panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") + } + return +} + +// A LazyDLL implements access to a single DLL. +// It will delay the load of the DLL until the first +// call to its Handle method or to one of its +// LazyProc's Addr method. +type LazyDLL struct { + mu sync.Mutex + dll *DLL // non nil once DLL is loaded + Name string +} + +// Load loads DLL file d.Name into memory. It returns an error if fails. +// Load will not try to load DLL, if it is already loaded into memory. +func (d *LazyDLL) Load() error { + // Non-racy version of: + // if d.dll == nil { + if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil { + d.mu.Lock() + defer d.mu.Unlock() + if d.dll == nil { + dll, e := LoadDLL(d.Name) + if e != nil { + return e + } + // Non-racy version of: + // d.dll = dll + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll)) + } + } + return nil +} + +// mustLoad is like Load but panics if search fails. +func (d *LazyDLL) mustLoad() { + e := d.Load() + if e != nil { + panic(e) + } +} + +// Handle returns d's module handle. +func (d *LazyDLL) Handle() uintptr { + d.mustLoad() + return uintptr(d.dll.Handle) +} + +// NewProc returns a LazyProc for accessing the named procedure in the DLL d. +func (d *LazyDLL) NewProc(name string) *LazyProc { + return &LazyProc{l: d, Name: name} +} + +// NewLazyDLL creates new LazyDLL associated with DLL file. +func NewLazyDLL(name string) *LazyDLL { + return &LazyDLL{Name: name} +} + +// A LazyProc implements access to a procedure inside a LazyDLL. +// It delays the lookup until the Addr method is called. +type LazyProc struct { + mu sync.Mutex + Name string + l *LazyDLL + proc *Proc +} + +// Find searches DLL 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.dll.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 15 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 windows.Errno. +func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { + p.mustFind() + return p.proc.Call(a...) +} diff --git a/vendor/golang.org/x/sys/windows/env_unset.go b/vendor/golang.org/x/sys/windows/env_unset.go new file mode 100644 index 0000000..999ffac --- /dev/null +++ b/vendor/golang.org/x/sys/windows/env_unset.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 go1.4 + +package windows + +import "syscall" + +func Unsetenv(key string) error { + // This was added in Go 1.4. + return syscall.Unsetenv(key) +} diff --git a/vendor/golang.org/x/sys/windows/env_windows.go b/vendor/golang.org/x/sys/windows/env_windows.go new file mode 100644 index 0000000..a9d8ef4 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/env_windows.go @@ -0,0 +1,25 @@ +// 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. + +// Windows environment variables. + +package windows + +import "syscall" + +func Getenv(key string) (value string, found bool) { + return syscall.Getenv(key) +} + +func Setenv(key, value string) error { + return syscall.Setenv(key, value) +} + +func Clearenv() { + syscall.Clearenv() +} + +func Environ() []string { + return syscall.Environ() +} diff --git a/vendor/golang.org/x/sys/windows/eventlog.go b/vendor/golang.org/x/sys/windows/eventlog.go new file mode 100644 index 0000000..40af946 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/eventlog.go @@ -0,0 +1,20 @@ +// 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. + +// +build windows + +package windows + +const ( + EVENTLOG_SUCCESS = 0 + EVENTLOG_ERROR_TYPE = 1 + EVENTLOG_WARNING_TYPE = 2 + EVENTLOG_INFORMATION_TYPE = 4 + EVENTLOG_AUDIT_SUCCESS = 8 + EVENTLOG_AUDIT_FAILURE = 16 +) + +//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW +//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource +//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW diff --git a/vendor/golang.org/x/sys/windows/exec_windows.go b/vendor/golang.org/x/sys/windows/exec_windows.go new file mode 100644 index 0000000..3606c3a --- /dev/null +++ b/vendor/golang.org/x/sys/windows/exec_windows.go @@ -0,0 +1,97 @@ +// 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. + +// Fork, exec, wait, etc. + +package windows + +// EscapeArg rewrites command line argument s as prescribed +// in http://msdn.microsoft.com/en-us/library/ms880421. +// This function returns "" (2 double quotes) if s is empty. +// Alternatively, these transformations are done: +// - every back slash (\) is doubled, but only if immediately +// followed by double quote ("); +// - every double quote (") is escaped by back slash (\); +// - finally, s is wrapped with double quotes (arg -> "arg"), +// but only if there is space or tab inside s. +func EscapeArg(s string) string { + if len(s) == 0 { + return "\"\"" + } + n := len(s) + hasSpace := false + for i := 0; i < len(s); i++ { + switch s[i] { + case '"', '\\': + n++ + case ' ', '\t': + hasSpace = true + } + } + if hasSpace { + n += 2 + } + if n == len(s) { + return s + } + + qs := make([]byte, n) + j := 0 + if hasSpace { + qs[j] = '"' + j++ + } + slashes := 0 + for i := 0; i < len(s); i++ { + switch s[i] { + default: + slashes = 0 + qs[j] = s[i] + case '\\': + slashes++ + qs[j] = s[i] + case '"': + for ; slashes > 0; slashes-- { + qs[j] = '\\' + j++ + } + qs[j] = '\\' + j++ + qs[j] = s[i] + } + j++ + } + if hasSpace { + for ; slashes > 0; slashes-- { + qs[j] = '\\' + j++ + } + qs[j] = '"' + j++ + } + return string(qs[:j]) +} + +func CloseOnExec(fd Handle) { + SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0) +} + +// FullPath retrieves the full path of the specified file. +func FullPath(name string) (path string, err error) { + p, err := UTF16PtrFromString(name) + if err != nil { + return "", err + } + n := uint32(100) + for { + buf := make([]uint16, n) + n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil) + if err != nil { + return "", err + } + if n <= uint32(len(buf)) { + return UTF16ToString(buf[:n]), nil + } + } +} diff --git a/vendor/golang.org/x/sys/windows/race.go b/vendor/golang.org/x/sys/windows/race.go new file mode 100644 index 0000000..343e18a --- /dev/null +++ b/vendor/golang.org/x/sys/windows/race.go @@ -0,0 +1,30 @@ +// 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. + +// +build windows,race + +package windows + +import ( + "runtime" + "unsafe" +) + +const raceenabled = true + +func raceAcquire(addr unsafe.Pointer) { + runtime.RaceAcquire(addr) +} + +func raceReleaseMerge(addr unsafe.Pointer) { + runtime.RaceReleaseMerge(addr) +} + +func raceReadRange(addr unsafe.Pointer, len int) { + runtime.RaceReadRange(addr, len) +} + +func raceWriteRange(addr unsafe.Pointer, len int) { + runtime.RaceWriteRange(addr, len) +} diff --git a/vendor/golang.org/x/sys/windows/race0.go b/vendor/golang.org/x/sys/windows/race0.go new file mode 100644 index 0000000..17af843 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/race0.go @@ -0,0 +1,25 @@ +// 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. + +// +build windows,!race + +package windows + +import ( + "unsafe" +) + +const raceenabled = false + +func raceAcquire(addr unsafe.Pointer) { +} + +func raceReleaseMerge(addr unsafe.Pointer) { +} + +func raceReadRange(addr unsafe.Pointer, len int) { +} + +func raceWriteRange(addr unsafe.Pointer, len int) { +} diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go new file mode 100644 index 0000000..ca09bdd --- /dev/null +++ b/vendor/golang.org/x/sys/windows/security_windows.go @@ -0,0 +1,435 @@ +// 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 windows + +import ( + "syscall" + "unsafe" +) + +const ( + STANDARD_RIGHTS_REQUIRED = 0xf0000 + STANDARD_RIGHTS_READ = 0x20000 + STANDARD_RIGHTS_WRITE = 0x20000 + STANDARD_RIGHTS_EXECUTE = 0x20000 + STANDARD_RIGHTS_ALL = 0x1F0000 +) + +const ( + NameUnknown = 0 + NameFullyQualifiedDN = 1 + NameSamCompatible = 2 + NameDisplay = 3 + NameUniqueId = 6 + NameCanonical = 7 + NameUserPrincipal = 8 + NameCanonicalEx = 9 + NameServicePrincipal = 10 + NameDnsDomain = 12 +) + +// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. +// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx +//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW +//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW + +// TranslateAccountName converts a directory service +// object name from one format to another. +func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) { + u, e := UTF16PtrFromString(username) + if e != nil { + return "", e + } + n := uint32(50) + for { + b := make([]uint16, n) + e = TranslateName(u, from, to, &b[0], &n) + if e == nil { + return UTF16ToString(b[:n]), nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return "", e + } + if n <= uint32(len(b)) { + return "", e + } + } +} + +const ( + // do not reorder + NetSetupUnknownStatus = iota + NetSetupUnjoined + NetSetupWorkgroupName + NetSetupDomainName +) + +type UserInfo10 struct { + Name *uint16 + Comment *uint16 + UsrComment *uint16 + FullName *uint16 +} + +//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo +//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation +//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree + +const ( + // do not reorder + SidTypeUser = 1 + iota + SidTypeGroup + SidTypeDomain + SidTypeAlias + SidTypeWellKnownGroup + SidTypeDeletedAccount + SidTypeInvalid + SidTypeUnknown + SidTypeComputer + SidTypeLabel +) + +type SidIdentifierAuthority struct { + Value [6]byte +} + +var ( + SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}} + SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}} + SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}} + SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}} + SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}} + SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}} + SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}} +) + +const ( + SECURITY_NULL_RID = 0 + SECURITY_WORLD_RID = 0 + SECURITY_LOCAL_RID = 0 + SECURITY_CREATOR_OWNER_RID = 0 + SECURITY_CREATOR_GROUP_RID = 1 + SECURITY_DIALUP_RID = 1 + SECURITY_NETWORK_RID = 2 + SECURITY_BATCH_RID = 3 + SECURITY_INTERACTIVE_RID = 4 + SECURITY_LOGON_IDS_RID = 5 + SECURITY_SERVICE_RID = 6 + SECURITY_LOCAL_SYSTEM_RID = 18 + SECURITY_BUILTIN_DOMAIN_RID = 32 + SECURITY_PRINCIPAL_SELF_RID = 10 + SECURITY_CREATOR_OWNER_SERVER_RID = 0x2 + SECURITY_CREATOR_GROUP_SERVER_RID = 0x3 + SECURITY_LOGON_IDS_RID_COUNT = 0x3 + SECURITY_ANONYMOUS_LOGON_RID = 0x7 + SECURITY_PROXY_RID = 0x8 + SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9 + SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID + SECURITY_AUTHENTICATED_USER_RID = 0xb + SECURITY_RESTRICTED_CODE_RID = 0xc + SECURITY_NT_NON_UNIQUE_RID = 0x15 +) + +//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW +//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW +//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW +//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW +//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid +//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid +//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid +//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid +//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid + +// The security identifier (SID) structure is a variable-length +// structure used to uniquely identify users or groups. +type SID struct{} + +// StringToSid converts a string-format security identifier +// sid into a valid, functional sid. +func StringToSid(s string) (*SID, error) { + var sid *SID + p, e := UTF16PtrFromString(s) + if e != nil { + return nil, e + } + e = ConvertStringSidToSid(p, &sid) + if e != nil { + return nil, e + } + defer LocalFree((Handle)(unsafe.Pointer(sid))) + return sid.Copy() +} + +// LookupSID retrieves a security identifier sid for the account +// and the name of the domain on which the account was found. +// System specify target computer to search. +func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) { + if len(account) == 0 { + return nil, "", 0, syscall.EINVAL + } + acc, e := UTF16PtrFromString(account) + if e != nil { + return nil, "", 0, e + } + var sys *uint16 + if len(system) > 0 { + sys, e = UTF16PtrFromString(system) + if e != nil { + return nil, "", 0, e + } + } + n := uint32(50) + dn := uint32(50) + for { + b := make([]byte, n) + db := make([]uint16, dn) + sid = (*SID)(unsafe.Pointer(&b[0])) + e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType) + if e == nil { + return sid, UTF16ToString(db), accType, nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return nil, "", 0, e + } + if n <= uint32(len(b)) { + return nil, "", 0, e + } + } +} + +// String converts sid to a string format +// suitable for display, storage, or transmission. +func (sid *SID) String() (string, error) { + var s *uint16 + e := ConvertSidToStringSid(sid, &s) + if e != nil { + return "", e + } + defer LocalFree((Handle)(unsafe.Pointer(s))) + return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil +} + +// Len returns the length, in bytes, of a valid security identifier sid. +func (sid *SID) Len() int { + return int(GetLengthSid(sid)) +} + +// Copy creates a duplicate of security identifier sid. +func (sid *SID) Copy() (*SID, error) { + b := make([]byte, sid.Len()) + sid2 := (*SID)(unsafe.Pointer(&b[0])) + e := CopySid(uint32(len(b)), sid2, sid) + if e != nil { + return nil, e + } + return sid2, nil +} + +// LookupAccount retrieves the name of the account for this sid +// and the name of the first domain on which this sid is found. +// System specify target computer to search for. +func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) { + var sys *uint16 + if len(system) > 0 { + sys, err = UTF16PtrFromString(system) + if err != nil { + return "", "", 0, err + } + } + n := uint32(50) + dn := uint32(50) + for { + b := make([]uint16, n) + db := make([]uint16, dn) + e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType) + if e == nil { + return UTF16ToString(b), UTF16ToString(db), accType, nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return "", "", 0, e + } + if n <= uint32(len(b)) { + return "", "", 0, e + } + } +} + +const ( + // do not reorder + TOKEN_ASSIGN_PRIMARY = 1 << iota + TOKEN_DUPLICATE + TOKEN_IMPERSONATE + TOKEN_QUERY + TOKEN_QUERY_SOURCE + TOKEN_ADJUST_PRIVILEGES + TOKEN_ADJUST_GROUPS + TOKEN_ADJUST_DEFAULT + + TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | + TOKEN_ASSIGN_PRIMARY | + TOKEN_DUPLICATE | + TOKEN_IMPERSONATE | + TOKEN_QUERY | + TOKEN_QUERY_SOURCE | + TOKEN_ADJUST_PRIVILEGES | + TOKEN_ADJUST_GROUPS | + TOKEN_ADJUST_DEFAULT + TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY + TOKEN_WRITE = STANDARD_RIGHTS_WRITE | + TOKEN_ADJUST_PRIVILEGES | + TOKEN_ADJUST_GROUPS | + TOKEN_ADJUST_DEFAULT + TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE +) + +const ( + // do not reorder + TokenUser = 1 + iota + TokenGroups + TokenPrivileges + TokenOwner + TokenPrimaryGroup + TokenDefaultDacl + TokenSource + TokenType + TokenImpersonationLevel + TokenStatistics + TokenRestrictedSids + TokenSessionId + TokenGroupsAndPrivileges + TokenSessionReference + TokenSandBoxInert + TokenAuditPolicy + TokenOrigin + TokenElevationType + TokenLinkedToken + TokenElevation + TokenHasRestrictions + TokenAccessInformation + TokenVirtualizationAllowed + TokenVirtualizationEnabled + TokenIntegrityLevel + TokenUIAccess + TokenMandatoryPolicy + TokenLogonSid + MaxTokenInfoClass +) + +type SIDAndAttributes struct { + Sid *SID + Attributes uint32 +} + +type Tokenuser struct { + User SIDAndAttributes +} + +type Tokenprimarygroup struct { + PrimaryGroup *SID +} + +type Tokengroups struct { + GroupCount uint32 + Groups [1]SIDAndAttributes +} + +//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken +//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation +//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW + +// An access token contains the security information for a logon session. +// The system creates an access token when a user logs on, and every +// process executed on behalf of the user has a copy of the token. +// The token identifies the user, the user's groups, and the user's +// privileges. The system uses the token to control access to securable +// objects and to control the ability of the user to perform various +// system-related operations on the local computer. +type Token Handle + +// OpenCurrentProcessToken opens the access token +// associated with current process. +func OpenCurrentProcessToken() (Token, error) { + p, e := GetCurrentProcess() + if e != nil { + return 0, e + } + var t Token + e = OpenProcessToken(p, TOKEN_QUERY, &t) + if e != nil { + return 0, e + } + return t, nil +} + +// Close releases access to access token. +func (t Token) Close() error { + return CloseHandle(Handle(t)) +} + +// getInfo retrieves a specified type of information about an access token. +func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) { + n := uint32(initSize) + for { + b := make([]byte, n) + e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) + if e == nil { + return unsafe.Pointer(&b[0]), nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return nil, e + } + if n <= uint32(len(b)) { + return nil, e + } + } +} + +// GetTokenUser retrieves access token t user account information. +func (t Token) GetTokenUser() (*Tokenuser, error) { + i, e := t.getInfo(TokenUser, 50) + if e != nil { + return nil, e + } + return (*Tokenuser)(i), nil +} + +// GetTokenGroups retrieves group accounts associated with access token t. +func (t Token) GetTokenGroups() (*Tokengroups, error) { + i, e := t.getInfo(TokenGroups, 50) + if e != nil { + return nil, e + } + return (*Tokengroups)(i), nil +} + +// GetTokenPrimaryGroup retrieves access token t primary group information. +// A pointer to a SID structure representing a group that will become +// the primary group of any objects created by a process using this access token. +func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) { + i, e := t.getInfo(TokenPrimaryGroup, 50) + if e != nil { + return nil, e + } + return (*Tokenprimarygroup)(i), nil +} + +// GetUserProfileDirectory retrieves path to the +// root directory of the access token t user's profile. +func (t Token) GetUserProfileDirectory() (string, error) { + n := uint32(100) + for { + b := make([]uint16, n) + e := GetUserProfileDirectory(t, &b[0], &n) + if e == nil { + return UTF16ToString(b), nil + } + if e != ERROR_INSUFFICIENT_BUFFER { + return "", e + } + if n <= uint32(len(b)) { + return "", e + } + } +} diff --git a/vendor/golang.org/x/sys/windows/service.go b/vendor/golang.org/x/sys/windows/service.go new file mode 100644 index 0000000..1c11d39 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/service.go @@ -0,0 +1,143 @@ +// 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. + +// +build windows + +package windows + +const ( + SC_MANAGER_CONNECT = 1 + SC_MANAGER_CREATE_SERVICE = 2 + SC_MANAGER_ENUMERATE_SERVICE = 4 + SC_MANAGER_LOCK = 8 + SC_MANAGER_QUERY_LOCK_STATUS = 16 + SC_MANAGER_MODIFY_BOOT_CONFIG = 32 + SC_MANAGER_ALL_ACCESS = 0xf003f +) + +//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW + +const ( + SERVICE_KERNEL_DRIVER = 1 + SERVICE_FILE_SYSTEM_DRIVER = 2 + SERVICE_ADAPTER = 4 + SERVICE_RECOGNIZER_DRIVER = 8 + SERVICE_WIN32_OWN_PROCESS = 16 + SERVICE_WIN32_SHARE_PROCESS = 32 + SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS + SERVICE_INTERACTIVE_PROCESS = 256 + SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER + SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS + + SERVICE_BOOT_START = 0 + SERVICE_SYSTEM_START = 1 + SERVICE_AUTO_START = 2 + SERVICE_DEMAND_START = 3 + SERVICE_DISABLED = 4 + + SERVICE_ERROR_IGNORE = 0 + SERVICE_ERROR_NORMAL = 1 + SERVICE_ERROR_SEVERE = 2 + SERVICE_ERROR_CRITICAL = 3 + + SC_STATUS_PROCESS_INFO = 0 + + SERVICE_STOPPED = 1 + SERVICE_START_PENDING = 2 + SERVICE_STOP_PENDING = 3 + SERVICE_RUNNING = 4 + SERVICE_CONTINUE_PENDING = 5 + SERVICE_PAUSE_PENDING = 6 + SERVICE_PAUSED = 7 + SERVICE_NO_CHANGE = 0xffffffff + + SERVICE_ACCEPT_STOP = 1 + SERVICE_ACCEPT_PAUSE_CONTINUE = 2 + SERVICE_ACCEPT_SHUTDOWN = 4 + SERVICE_ACCEPT_PARAMCHANGE = 8 + SERVICE_ACCEPT_NETBINDCHANGE = 16 + SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32 + SERVICE_ACCEPT_POWEREVENT = 64 + SERVICE_ACCEPT_SESSIONCHANGE = 128 + + SERVICE_CONTROL_STOP = 1 + SERVICE_CONTROL_PAUSE = 2 + SERVICE_CONTROL_CONTINUE = 3 + SERVICE_CONTROL_INTERROGATE = 4 + SERVICE_CONTROL_SHUTDOWN = 5 + SERVICE_CONTROL_PARAMCHANGE = 6 + SERVICE_CONTROL_NETBINDADD = 7 + SERVICE_CONTROL_NETBINDREMOVE = 8 + SERVICE_CONTROL_NETBINDENABLE = 9 + SERVICE_CONTROL_NETBINDDISABLE = 10 + SERVICE_CONTROL_DEVICEEVENT = 11 + SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12 + SERVICE_CONTROL_POWEREVENT = 13 + SERVICE_CONTROL_SESSIONCHANGE = 14 + + SERVICE_ACTIVE = 1 + SERVICE_INACTIVE = 2 + SERVICE_STATE_ALL = 3 + + SERVICE_QUERY_CONFIG = 1 + SERVICE_CHANGE_CONFIG = 2 + SERVICE_QUERY_STATUS = 4 + SERVICE_ENUMERATE_DEPENDENTS = 8 + SERVICE_START = 16 + SERVICE_STOP = 32 + SERVICE_PAUSE_CONTINUE = 64 + SERVICE_INTERROGATE = 128 + SERVICE_USER_DEFINED_CONTROL = 256 + SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL + SERVICE_RUNS_IN_SYSTEM_PROCESS = 1 + SERVICE_CONFIG_DESCRIPTION = 1 + SERVICE_CONFIG_FAILURE_ACTIONS = 2 + + NO_ERROR = 0 +) + +type SERVICE_STATUS struct { + ServiceType uint32 + CurrentState uint32 + ControlsAccepted uint32 + Win32ExitCode uint32 + ServiceSpecificExitCode uint32 + CheckPoint uint32 + WaitHint uint32 +} + +type SERVICE_TABLE_ENTRY struct { + ServiceName *uint16 + ServiceProc uintptr +} + +type QUERY_SERVICE_CONFIG struct { + ServiceType uint32 + StartType uint32 + ErrorControl uint32 + BinaryPathName *uint16 + LoadOrderGroup *uint16 + TagId uint32 + Dependencies *uint16 + ServiceStartName *uint16 + DisplayName *uint16 +} + +type SERVICE_DESCRIPTION struct { + Description *uint16 +} + +//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle +//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW +//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW +//sys DeleteService(service Handle) (err error) = advapi32.DeleteService +//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW +//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus +//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService +//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW +//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus +//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW +//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW +//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W +//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W diff --git a/vendor/golang.org/x/sys/windows/str.go b/vendor/golang.org/x/sys/windows/str.go new file mode 100644 index 0000000..917cc2a --- /dev/null +++ b/vendor/golang.org/x/sys/windows/str.go @@ -0,0 +1,22 @@ +// 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 windows + +package windows + +func itoa(val int) string { // do it here rather than with fmt to avoid dependency + if val < 0 { + return "-" + itoa(-val) + } + var buf [32]byte // big enough for int64 + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return string(buf[i:]) +} diff --git a/vendor/golang.org/x/sys/windows/syscall.go b/vendor/golang.org/x/sys/windows/syscall.go new file mode 100644 index 0000000..281cd66 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/syscall.go @@ -0,0 +1,77 @@ +// 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 windows + +// Package windows contains an interface to the low-level operating system +// primitives. OS details vary depending on the underlying system, and +// by default, godoc will display the OS-specific documentation for the current +// system. If you want godoc to display syscall documentation for another +// system, set $GOOS and $GOARCH to the desired system. For example, if +// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS +// to freebsd and $GOARCH to arm. +// The primary use of this package is inside other packages that provide a more +// portable interface to the system, such as "os", "time" and "net". Use +// those packages rather than this one if you can. +// For details of the functions and data types in this package consult +// the manuals for the appropriate operating system. +// These calls return err == nil to indicate success; otherwise +// err represents an operating system error describing the failure and +// holds a value of type syscall.Errno. +package windows + +import ( + "syscall" + "unsafe" +) + +// ByteSliceFromString returns a NUL-terminated slice of bytes +// containing the text of s. If s contains a NUL byte at any +// location, it returns (nil, syscall.EINVAL). +func ByteSliceFromString(s string) ([]byte, error) { + for i := 0; i < len(s); i++ { + if s[i] == 0 { + return nil, syscall.EINVAL + } + } + a := make([]byte, len(s)+1) + copy(a, s) + return a, nil +} + +// BytePtrFromString returns a pointer to a NUL-terminated array of +// bytes containing the text of s. If s contains a NUL byte at any +// location, it returns (nil, syscall.EINVAL). +func BytePtrFromString(s string) (*byte, error) { + a, err := ByteSliceFromString(s) + if err != nil { + return nil, err + } + return &a[0], nil +} + +// Single-word zero for use when we need a valid pointer to 0 bytes. +// See mksyscall.pl. +var _zero uintptr + +func (ts *Timespec) Unix() (sec int64, nsec int64) { + return int64(ts.Sec), int64(ts.Nsec) +} + +func (tv *Timeval) Unix() (sec int64, nsec int64) { + return int64(tv.Sec), int64(tv.Usec) * 1000 +} + +func (ts *Timespec) Nano() int64 { + return int64(ts.Sec)*1e9 + int64(ts.Nsec) +} + +func (tv *Timeval) Nano() int64 { + return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 +} + +// use is a no-op, but the compiler cannot see that it is. +// Calling use(p) ensures that p is kept live until that point. +//go:noescape +func use(p unsafe.Pointer) diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go new file mode 100644 index 0000000..75def60 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -0,0 +1,990 @@ +// 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. + +// Windows system calls. + +package windows + +import ( + errorspkg "errors" + "sync" + "syscall" + "unicode/utf16" + "unsafe" +) + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go + +type Handle uintptr + +const InvalidHandle = ^Handle(0) + +// StringToUTF16 is deprecated. Use UTF16FromString instead. +// If s contains a NUL byte this function panics instead of +// returning an error. +func StringToUTF16(s string) []uint16 { + a, err := UTF16FromString(s) + if err != nil { + panic("windows: string with NUL passed to StringToUTF16") + } + return a +} + +// UTF16FromString returns the UTF-16 encoding of the UTF-8 string +// s, with a terminating NUL added. If s contains a NUL byte at any +// location, it returns (nil, syscall.EINVAL). +func UTF16FromString(s string) ([]uint16, error) { + for i := 0; i < len(s); i++ { + if s[i] == 0 { + return nil, syscall.EINVAL + } + } + return utf16.Encode([]rune(s + "\x00")), nil +} + +// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s, +// with a terminating NUL removed. +func UTF16ToString(s []uint16) string { + for i, v := range s { + if v == 0 { + s = s[0:i] + break + } + } + return string(utf16.Decode(s)) +} + +// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead. +// If s contains a NUL byte this function panics instead of +// returning an error. +func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } + +// UTF16PtrFromString returns pointer to the UTF-16 encoding of +// the UTF-8 string s, with a terminating NUL added. If s +// contains a NUL byte at any location, it returns (nil, syscall.EINVAL). +func UTF16PtrFromString(s string) (*uint16, error) { + a, err := UTF16FromString(s) + if err != nil { + return nil, err + } + return &a[0], nil +} + +func Getpagesize() int { return 4096 } + +// Converts a Go function to a function pointer conforming +// 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 + +//sys GetLastError() (lasterr error) +//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW +//sys FreeLibrary(handle Handle) (err error) +//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) +//sys GetVersion() (ver uint32, err error) +//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW +//sys ExitProcess(exitcode uint32) +//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW +//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) +//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) +//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff] +//sys CloseHandle(handle Handle) (err error) +//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle] +//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW +//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW +//sys FindClose(handle Handle) (err error) +//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) +//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW +//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW +//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW +//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW +//sys DeleteFile(path *uint16) (err error) = DeleteFileW +//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW +//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW +//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW +//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW +//sys SetEndOfFile(handle Handle) (err error) +//sys GetSystemTimeAsFileTime(time *Filetime) +//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] +//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) +//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) +//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) +//sys CancelIo(s Handle) (err error) +//sys CancelIoEx(s Handle, o *Overlapped) (err error) +//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW +//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) +//sys TerminateProcess(handle Handle, exitcode uint32) (err error) +//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) +//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW +//sys GetCurrentProcess() (pseudoHandle Handle, err error) +//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) +//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) +//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] +//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW +//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) +//sys GetFileType(filehandle Handle) (n uint32, err error) +//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW +//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext +//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom +//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW +//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW +//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW +//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW +//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) +//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW +//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW +//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW +//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW +//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW +//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0] +//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) +//sys FlushFileBuffers(handle Handle) (err error) +//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW +//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW +//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW +//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW +//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) +//sys UnmapViewOfFile(addr uintptr) (err error) +//sys FlushViewOfFile(addr uintptr, length uintptr) (err error) +//sys VirtualLock(addr uintptr, length uintptr) (err error) +//sys VirtualUnlock(addr uintptr, length uintptr) (err error) +//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile +//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW +//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW +//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore +//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore +//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore +//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore +//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain +//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain +//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext +//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext +//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy +//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW +//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey +//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW +//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW +//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW +//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId +//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode +//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW +//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW +//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot +//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW +//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW +//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) +// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. +//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW +//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW +//sys GetCurrentThreadId() (id uint32) +//sys CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) = kernel32.CreateEventW +//sys SetEvent(event Handle) (err error) = kernel32.SetEvent + +// syscall interface implementation for other packages + +func Exit(code int) { ExitProcess(uint32(code)) } + +func makeInheritSa() *SecurityAttributes { + var sa SecurityAttributes + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + return &sa +} + +func Open(path string, mode int, perm uint32) (fd Handle, err error) { + if len(path) == 0 { + return InvalidHandle, ERROR_FILE_NOT_FOUND + } + pathp, err := UTF16PtrFromString(path) + if err != nil { + return InvalidHandle, err + } + var access uint32 + switch mode & (O_RDONLY | O_WRONLY | O_RDWR) { + case O_RDONLY: + access = GENERIC_READ + case O_WRONLY: + access = GENERIC_WRITE + case O_RDWR: + access = GENERIC_READ | GENERIC_WRITE + } + if mode&O_CREAT != 0 { + access |= GENERIC_WRITE + } + if mode&O_APPEND != 0 { + access &^= GENERIC_WRITE + access |= FILE_APPEND_DATA + } + sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE) + var sa *SecurityAttributes + if mode&O_CLOEXEC == 0 { + sa = makeInheritSa() + } + var createmode uint32 + switch { + case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): + createmode = CREATE_NEW + case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC): + createmode = CREATE_ALWAYS + case mode&O_CREAT == O_CREAT: + createmode = OPEN_ALWAYS + case mode&O_TRUNC == O_TRUNC: + createmode = TRUNCATE_EXISTING + default: + createmode = OPEN_EXISTING + } + h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0) + return h, e +} + +func Read(fd Handle, p []byte) (n int, err error) { + var done uint32 + e := ReadFile(fd, p, &done, nil) + if e != nil { + if e == ERROR_BROKEN_PIPE { + // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin + return 0, nil + } + return 0, e + } + if raceenabled { + if done > 0 { + raceWriteRange(unsafe.Pointer(&p[0]), int(done)) + } + raceAcquire(unsafe.Pointer(&ioSync)) + } + return int(done), nil +} + +func Write(fd Handle, p []byte) (n int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + var done uint32 + e := WriteFile(fd, p, &done, nil) + if e != nil { + return 0, e + } + if raceenabled && done > 0 { + raceReadRange(unsafe.Pointer(&p[0]), int(done)) + } + return int(done), nil +} + +var ioSync int64 + +func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) { + var w uint32 + switch whence { + case 0: + w = FILE_BEGIN + case 1: + w = FILE_CURRENT + case 2: + w = FILE_END + } + hi := int32(offset >> 32) + lo := int32(offset) + // use GetFileType to check pipe, pipe can't do seek + ft, _ := GetFileType(fd) + if ft == FILE_TYPE_PIPE { + return 0, syscall.EPIPE + } + rlo, e := SetFilePointer(fd, lo, &hi, w) + if e != nil { + return 0, e + } + return int64(hi)<<32 + int64(rlo), nil +} + +func Close(fd Handle) (err error) { + return CloseHandle(fd) +} + +var ( + Stdin = getStdHandle(STD_INPUT_HANDLE) + Stdout = getStdHandle(STD_OUTPUT_HANDLE) + Stderr = getStdHandle(STD_ERROR_HANDLE) +) + +func getStdHandle(h int) (fd Handle) { + r, _ := GetStdHandle(h) + CloseOnExec(r) + return r +} + +const ImplementsGetwd = true + +func Getwd() (wd string, err error) { + b := make([]uint16, 300) + n, e := GetCurrentDirectory(uint32(len(b)), &b[0]) + if e != nil { + return "", e + } + return string(utf16.Decode(b[0:n])), nil +} + +func Chdir(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return SetCurrentDirectory(pathp) +} + +func Mkdir(path string, mode uint32) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return CreateDirectory(pathp, nil) +} + +func Rmdir(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return RemoveDirectory(pathp) +} + +func Unlink(path string) (err error) { + pathp, err := UTF16PtrFromString(path) + if err != nil { + return err + } + return DeleteFile(pathp) +} + +func Rename(oldpath, newpath string) (err error) { + from, err := UTF16PtrFromString(oldpath) + if err != nil { + return err + } + to, err := UTF16PtrFromString(newpath) + if err != nil { + return err + } + return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) +} + +func ComputerName() (name string, err error) { + var n uint32 = MAX_COMPUTERNAME_LENGTH + 1 + b := make([]uint16, n) + e := GetComputerName(&b[0], &n) + if e != nil { + return "", e + } + return string(utf16.Decode(b[0:n])), nil +} + +func Ftruncate(fd Handle, length int64) (err error) { + curoffset, e := Seek(fd, 0, 1) + if e != nil { + return e + } + defer Seek(fd, curoffset, 0) + _, e = Seek(fd, length, 0) + if e != nil { + return e + } + e = SetEndOfFile(fd) + if e != nil { + return e + } + return nil +} + +func Gettimeofday(tv *Timeval) (err error) { + var ft Filetime + GetSystemTimeAsFileTime(&ft) + *tv = NsecToTimeval(ft.Nanoseconds()) + return nil +} + +func Pipe(p []Handle) (err error) { + if len(p) != 2 { + return syscall.EINVAL + } + var r, w Handle + e := CreatePipe(&r, &w, makeInheritSa(), 0) + if e != nil { + return e + } + p[0] = r + p[1] = w + return nil +} + +func Utimes(path string, tv []Timeval) (err error) { + if len(tv) != 2 { + return syscall.EINVAL + } + pathp, e := UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := CreateFile(pathp, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer Close(h) + a := NsecToFiletime(tv[0].Nanoseconds()) + w := NsecToFiletime(tv[1].Nanoseconds()) + return SetFileTime(h, nil, &a, &w) +} + +func UtimesNano(path string, ts []Timespec) (err error) { + if len(ts) != 2 { + return syscall.EINVAL + } + pathp, e := UTF16PtrFromString(path) + if e != nil { + return e + } + h, e := CreateFile(pathp, + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) + if e != nil { + return e + } + defer Close(h) + a := NsecToFiletime(TimespecToNsec(ts[0])) + w := NsecToFiletime(TimespecToNsec(ts[1])) + return SetFileTime(h, nil, &a, &w) +} + +func Fsync(fd Handle) (err error) { + return FlushFileBuffers(fd) +} + +func Chmod(path string, mode uint32) (err error) { + if mode == 0 { + return syscall.EINVAL + } + p, e := UTF16PtrFromString(path) + if e != nil { + return e + } + attrs, e := GetFileAttributes(p) + if e != nil { + return e + } + if mode&S_IWRITE != 0 { + attrs &^= FILE_ATTRIBUTE_READONLY + } else { + attrs |= FILE_ATTRIBUTE_READONLY + } + return SetFileAttributes(p, attrs) +} + +func LoadCancelIoEx() error { + return procCancelIoEx.Find() +} + +func LoadSetFileCompletionNotificationModes() error { + return procSetFileCompletionNotificationModes.Find() +} + +// net api calls + +const socket_error = uintptr(^uint32(0)) + +//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup +//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup +//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl +//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 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 +//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown +//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket +//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx +//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs +//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv +//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend +//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom +//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo +//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname +//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname +//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs +//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname +//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W +//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree +//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W +//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW +//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW +//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry +//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo +//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes +//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW +//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses +//sys GetACP() (acp uint32) = kernel32.GetACP +//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar + +// For testing: clients can set this flag to force +// creation of IPv6 sockets to return EAFNOSUPPORT. +var SocketDisableIPv6 bool + +type RawSockaddrInet4 struct { + Family uint16 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Family uint16 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddr struct { + Family uint16 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [96]int8 +} + +type Sockaddr interface { + sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs +} + +type SockaddrInet4 struct { + Port int + Addr [4]byte + raw RawSockaddrInet4 +} + +func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, syscall.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), int32(unsafe.Sizeof(sa.raw)), nil +} + +type SockaddrInet6 struct { + Port int + ZoneId uint32 + Addr [16]byte + raw RawSockaddrInet6 +} + +func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) { + if sa.Port < 0 || sa.Port > 0xFFFF { + return nil, 0, syscall.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), int32(unsafe.Sizeof(sa.raw)), nil +} + +type SockaddrUnix struct { + Name string +} + +func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) { + // TODO(brainman): implement SockaddrUnix.sockaddr() + return nil, 0, syscall.EWINDOWS +} + +func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { + switch rsa.Addr.Family { + case AF_UNIX: + return nil, syscall.EWINDOWS + + 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, syscall.EAFNOSUPPORT +} + +func Socket(domain, typ, proto int) (fd Handle, err error) { + if domain == AF_INET6 && SocketDisableIPv6 { + return InvalidHandle, syscall.EAFNOSUPPORT + } + return socket(int32(domain), int32(typ), int32(proto)) +} + +func SetsockoptInt(fd Handle, level, opt int, value int) (err error) { + v := int32(value) + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))) +} + +func Bind(fd Handle, sa Sockaddr) (err error) { + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return bind(fd, ptr, n) +} + +func Connect(fd Handle, sa Sockaddr) (err error) { + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return connect(fd, ptr, n) +} + +func Getsockname(fd Handle) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + if err = getsockname(fd, &rsa, &l); err != nil { + return + } + return rsa.Sockaddr() +} + +func Getpeername(fd Handle) (sa Sockaddr, err error) { + var rsa RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + if err = getpeername(fd, &rsa, &l); err != nil { + return + } + return rsa.Sockaddr() +} + +func Listen(s Handle, n int) (err error) { + return listen(s, int32(n)) +} + +func Shutdown(fd Handle, how int) (err error) { + return shutdown(fd, int32(how)) +} + +func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) { + rsa, l, err := to.sockaddr() + if err != nil { + return err + } + return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine) +} + +func LoadGetAddrInfo() error { + return procGetAddrInfoW.Find() +} + +var connectExFunc struct { + once sync.Once + addr uintptr + err error +} + +func LoadConnectEx() error { + connectExFunc.once.Do(func() { + var s Handle + s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) + if connectExFunc.err != nil { + return + } + defer CloseHandle(s) + var n uint32 + connectExFunc.err = WSAIoctl(s, + SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_CONNECTEX)), + uint32(unsafe.Sizeof(WSAID_CONNECTEX)), + (*byte)(unsafe.Pointer(&connectExFunc.addr)), + uint32(unsafe.Sizeof(connectExFunc.addr)), + &n, nil, 0) + }) + return connectExFunc.err +} + +func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.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 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error { + err := LoadConnectEx() + if err != nil { + return errorspkg.New("failed to find ConnectEx: " + err.Error()) + } + ptr, n, err := sa.sockaddr() + if err != nil { + return err + } + return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped) +} + +// Invented structures to support what package os expects. +type Rusage struct { + CreationTime Filetime + ExitTime Filetime + KernelTime Filetime + UserTime Filetime +} + +type WaitStatus struct { + ExitCode uint32 +} + +func (w WaitStatus) Exited() bool { return true } + +func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) } + +func (w WaitStatus) Signal() Signal { return -1 } + +func (w WaitStatus) CoreDump() bool { return false } + +func (w WaitStatus) Stopped() bool { return false } + +func (w WaitStatus) Continued() bool { return false } + +func (w WaitStatus) StopSignal() Signal { return -1 } + +func (w WaitStatus) Signaled() bool { return false } + +func (w WaitStatus) TrapCause() int { return -1 } + +// Timespec is an invented structure on Windows, but here for +// consistency with the corresponding package for other operating systems. +type Timespec struct { + Sec int64 + Nsec int64 +} + +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 +} + +// TODO(brainman): fix all needed for net + +func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, syscall.EWINDOWS } +func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) { + return 0, nil, syscall.EWINDOWS +} +func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return syscall.EWINDOWS } +func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return syscall.EWINDOWS } + +// The Linger struct is wrong but we only noticed after Go 1. +// sysLinger is the real system call structure. + +// BUG(brainman): The definition of Linger is not appropriate for direct use +// with Setsockopt and Getsockopt. +// Use SetsockoptLinger instead. + +type Linger struct { + Onoff int32 + Linger int32 +} + +type sysLinger struct { + Onoff uint16 + Linger uint16 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, syscall.EWINDOWS } + +func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { + sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)} + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys))) +} + +func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) { + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4) +} +func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) { + return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq))) +} +func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { + return syscall.EWINDOWS +} + +func Getpid() (pid int) { return int(getCurrentProcessId()) } + +func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) { + // NOTE(rsc): The Win32finddata struct is wrong for the system call: + // the two paths are each one uint16 short. Use the correct struct, + // a win32finddata1, and then copy the results out. + // There is no loss of expressivity here, because the final + // uint16, if it is used, is supposed to be a NUL, and Go doesn't need that. + // For Go 1.1, we might avoid the allocation of win32finddata1 here + // by adding a final Bug [2]uint16 field to the struct and then + // adjusting the fields in the result directly. + var data1 win32finddata1 + handle, err = findFirstFile1(name, &data1) + if err == nil { + copyFindData(data, &data1) + } + return +} + +func FindNextFile(handle Handle, data *Win32finddata) (err error) { + var data1 win32finddata1 + err = findNextFile1(handle, &data1) + if err == nil { + copyFindData(data, &data1) + } + return +} + +func getProcessEntry(pid int) (*ProcessEntry32, error) { + snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err + } + defer CloseHandle(snapshot) + var procEntry ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = Process32First(snapshot, &procEntry); err != nil { + return nil, err + } + for { + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil + } + err = Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err + } + } +} + +func Getppid() (ppid int) { + pe, err := getProcessEntry(Getpid()) + if err != nil { + return -1 + } + return int(pe.ParentProcessID) +} + +// TODO(brainman): fix all needed for os +func Fchdir(fd Handle) (err error) { return syscall.EWINDOWS } +func Link(oldpath, newpath string) (err error) { return syscall.EWINDOWS } +func Symlink(path, link string) (err error) { return syscall.EWINDOWS } + +func Fchmod(fd Handle, mode uint32) (err error) { return syscall.EWINDOWS } +func Chown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS } +func Lchown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS } +func Fchown(fd Handle, uid int, gid int) (err error) { return syscall.EWINDOWS } + +func Getuid() (uid int) { return -1 } +func Geteuid() (euid int) { return -1 } +func Getgid() (gid int) { return -1 } +func Getegid() (egid int) { return -1 } +func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS } + +type Signal int + +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)) +} + +func LoadCreateSymbolicLink() error { + return procCreateSymbolicLinkW.Find() +} + +// Readlink returns the destination of the named symbolic link. +func Readlink(path string, buf []byte) (n int, err error) { + fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0) + if err != nil { + return -1, err + } + defer CloseHandle(fd) + + rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE) + var bytesReturned uint32 + err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) + if err != nil { + return -1, err + } + + rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0])) + var s string + switch rdb.ReparseTag { + case IO_REPARSE_TAG_SYMLINK: + data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) + p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) + s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2]) + case IO_REPARSE_TAG_MOUNT_POINT: + data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) + p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) + s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2]) + default: + // the path is not a symlink or junction but another type of reparse + // point + return -1, syscall.ENOENT + } + n = copy(buf, []byte(s)) + + return n, nil +} diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go new file mode 100644 index 0000000..10dd30a --- /dev/null +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -0,0 +1,2220 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package windows + +import "unsafe" +import "syscall" + +var _ unsafe.Pointer + +var ( + modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + modshell32 = syscall.NewLazyDLL("shell32.dll") + modmswsock = syscall.NewLazyDLL("mswsock.dll") + modcrypt32 = syscall.NewLazyDLL("crypt32.dll") + modws2_32 = syscall.NewLazyDLL("ws2_32.dll") + moddnsapi = syscall.NewLazyDLL("dnsapi.dll") + modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") + modsecur32 = syscall.NewLazyDLL("secur32.dll") + modnetapi32 = syscall.NewLazyDLL("netapi32.dll") + moduserenv = syscall.NewLazyDLL("userenv.dll") + + procRegisterEventSourceW = modadvapi32.NewProc("RegisterEventSourceW") + procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource") + procReportEventW = modadvapi32.NewProc("ReportEventW") + procOpenSCManagerW = modadvapi32.NewProc("OpenSCManagerW") + procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle") + procCreateServiceW = modadvapi32.NewProc("CreateServiceW") + procOpenServiceW = modadvapi32.NewProc("OpenServiceW") + procDeleteService = modadvapi32.NewProc("DeleteService") + procStartServiceW = modadvapi32.NewProc("StartServiceW") + procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") + procControlService = modadvapi32.NewProc("ControlService") + procStartServiceCtrlDispatcherW = modadvapi32.NewProc("StartServiceCtrlDispatcherW") + procSetServiceStatus = modadvapi32.NewProc("SetServiceStatus") + procChangeServiceConfigW = modadvapi32.NewProc("ChangeServiceConfigW") + procQueryServiceConfigW = modadvapi32.NewProc("QueryServiceConfigW") + procChangeServiceConfig2W = modadvapi32.NewProc("ChangeServiceConfig2W") + procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W") + procGetLastError = modkernel32.NewProc("GetLastError") + procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") + procFreeLibrary = modkernel32.NewProc("FreeLibrary") + procGetProcAddress = modkernel32.NewProc("GetProcAddress") + procGetVersion = modkernel32.NewProc("GetVersion") + procFormatMessageW = modkernel32.NewProc("FormatMessageW") + procExitProcess = modkernel32.NewProc("ExitProcess") + procCreateFileW = modkernel32.NewProc("CreateFileW") + procReadFile = modkernel32.NewProc("ReadFile") + procWriteFile = modkernel32.NewProc("WriteFile") + procSetFilePointer = modkernel32.NewProc("SetFilePointer") + procCloseHandle = modkernel32.NewProc("CloseHandle") + procGetStdHandle = modkernel32.NewProc("GetStdHandle") + procFindFirstFileW = modkernel32.NewProc("FindFirstFileW") + procFindNextFileW = modkernel32.NewProc("FindNextFileW") + procFindClose = modkernel32.NewProc("FindClose") + procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle") + procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") + procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") + procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW") + procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW") + procDeleteFileW = modkernel32.NewProc("DeleteFileW") + procMoveFileW = modkernel32.NewProc("MoveFileW") + procMoveFileExW = modkernel32.NewProc("MoveFileExW") + procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") + procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") + procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") + procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime") + procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus") + procCancelIo = modkernel32.NewProc("CancelIo") + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCreateProcessW = modkernel32.NewProc("CreateProcessW") + procOpenProcess = modkernel32.NewProc("OpenProcess") + procTerminateProcess = modkernel32.NewProc("TerminateProcess") + procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess") + procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW") + procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess") + procGetProcessTimes = modkernel32.NewProc("GetProcessTimes") + procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") + procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") + procGetTempPathW = modkernel32.NewProc("GetTempPathW") + procCreatePipe = modkernel32.NewProc("CreatePipe") + procGetFileType = modkernel32.NewProc("GetFileType") + procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW") + procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext") + procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom") + procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW") + procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW") + procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW") + procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") + procSetFileTime = modkernel32.NewProc("SetFileTime") + procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW") + procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW") + procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW") + procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") + procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") + procLocalFree = modkernel32.NewProc("LocalFree") + procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") + procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers") + procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW") + procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW") + procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW") + procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW") + procMapViewOfFile = modkernel32.NewProc("MapViewOfFile") + procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile") + procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile") + procVirtualLock = modkernel32.NewProc("VirtualLock") + procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") + procTransmitFile = modmswsock.NewProc("TransmitFile") + procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW") + procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW") + procCertOpenStore = modcrypt32.NewProc("CertOpenStore") + procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore") + procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore") + procCertCloseStore = modcrypt32.NewProc("CertCloseStore") + procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain") + procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain") + procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext") + procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext") + procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy") + procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW") + procRegCloseKey = modadvapi32.NewProc("RegCloseKey") + procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW") + procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW") + procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW") + procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") + procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") + procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") + procReadConsoleW = modkernel32.NewProc("ReadConsoleW") + procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") + procProcess32FirstW = modkernel32.NewProc("Process32FirstW") + procProcess32NextW = modkernel32.NewProc("Process32NextW") + procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") + procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") + procCreateHardLinkW = modkernel32.NewProc("CreateHardLinkW") + procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId") + procCreateEventW = modkernel32.NewProc("CreateEventW") + procSetEvent = modkernel32.NewProc("SetEvent") + procWSAStartup = modws2_32.NewProc("WSAStartup") + procWSACleanup = modws2_32.NewProc("WSACleanup") + procWSAIoctl = modws2_32.NewProc("WSAIoctl") + procsocket = modws2_32.NewProc("socket") + procsetsockopt = modws2_32.NewProc("setsockopt") + procgetsockopt = modws2_32.NewProc("getsockopt") + procbind = modws2_32.NewProc("bind") + procconnect = modws2_32.NewProc("connect") + procgetsockname = modws2_32.NewProc("getsockname") + procgetpeername = modws2_32.NewProc("getpeername") + proclisten = modws2_32.NewProc("listen") + procshutdown = modws2_32.NewProc("shutdown") + procclosesocket = modws2_32.NewProc("closesocket") + procAcceptEx = modmswsock.NewProc("AcceptEx") + procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs") + procWSARecv = modws2_32.NewProc("WSARecv") + procWSASend = modws2_32.NewProc("WSASend") + procWSARecvFrom = modws2_32.NewProc("WSARecvFrom") + procWSASendTo = modws2_32.NewProc("WSASendTo") + procgethostbyname = modws2_32.NewProc("gethostbyname") + procgetservbyname = modws2_32.NewProc("getservbyname") + procntohs = modws2_32.NewProc("ntohs") + procgetprotobyname = modws2_32.NewProc("getprotobyname") + procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W") + procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") + procDnsNameCompare_W = moddnsapi.NewProc("DnsNameCompare_W") + procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW") + procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW") + procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") + procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procGetACP = modkernel32.NewProc("GetACP") + procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") + procTranslateNameW = modsecur32.NewProc("TranslateNameW") + procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") + procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") + procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") + procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") + procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW") + procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") + procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") + procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") + procGetLengthSid = modadvapi32.NewProc("GetLengthSid") + procCopySid = modadvapi32.NewProc("CopySid") + procAllocateAndInitializeSid = modadvapi32.NewProc("AllocateAndInitializeSid") + procFreeSid = modadvapi32.NewProc("FreeSid") + procEqualSid = modadvapi32.NewProc("EqualSid") + procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") + procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") + procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") +) + +func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procRegisterEventSourceW.Addr(), 2, uintptr(unsafe.Pointer(uncServerName)), uintptr(unsafe.Pointer(sourceName)), 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeregisterEventSource(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDeregisterEventSource.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procReportEventW.Addr(), 9, uintptr(log), uintptr(etype), uintptr(category), uintptr(eventId), uintptr(usrSId), uintptr(numStrings), uintptr(dataSize), uintptr(unsafe.Pointer(strings)), uintptr(unsafe.Pointer(rawData))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CloseServiceHandle(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procCloseServiceHandle.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall15(procCreateServiceW.Addr(), 13, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteService(service Handle) (err error) { + r1, _, e1 := syscall.Syscall(procDeleteService.Addr(), 1, uintptr(service), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procStartServiceW.Addr(), 3, uintptr(service), uintptr(numArgs), uintptr(unsafe.Pointer(argVectors))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(status)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procControlService.Addr(), 3, uintptr(service), uintptr(control), uintptr(unsafe.Pointer(status))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) { + r1, _, e1 := syscall.Syscall(procStartServiceCtrlDispatcherW.Addr(), 1, uintptr(unsafe.Pointer(serviceTable)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) { + r1, _, e1 := syscall.Syscall(procSetServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(serviceStatus)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) { + r1, _, e1 := syscall.Syscall12(procChangeServiceConfigW.Addr(), 11, uintptr(service), uintptr(serviceType), uintptr(startType), uintptr(errorControl), uintptr(unsafe.Pointer(binaryPathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), uintptr(unsafe.Pointer(displayName)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procQueryServiceConfigW.Addr(), 4, uintptr(service), uintptr(unsafe.Pointer(serviceConfig)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) { + r1, _, e1 := syscall.Syscall(procChangeServiceConfig2W.Addr(), 3, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(info))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procQueryServiceConfig2W.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLastError() (lasterr error) { + r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0) + if r0 != 0 { + lasterr = syscall.Errno(r0) + } + return +} + +func LoadLibrary(libname string) (handle Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(libname) + if err != nil { + return + } + return _LoadLibrary(_p0) +} + +func _LoadLibrary(libname *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FreeLibrary(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(procname) + if err != nil { + return + } + return _GetProcAddress(module, _p0) +} + +func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { + r0, _, e1 := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0) + proc = uintptr(r0) + if proc == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetVersion() (ver uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetVersion.Addr(), 0, 0, 0, 0) + ver = uint32(r0) + if ver == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) { + var _p0 *uint16 + if len(buf) > 0 { + _p0 = &buf[0] + } + r0, _, e1 := syscall.Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ExitProcess(exitcode uint32) { + syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) + return +} + +func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := syscall.Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } + r1, _, e1 := syscall.Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) { + r0, _, e1 := syscall.Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) + newlowoffset = uint32(r0) + if newlowoffset == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CloseHandle(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetStdHandle(stdhandle int) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func findNextFile1(handle Handle, data *win32finddata1) (err error) { + r1, _, e1 := syscall.Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FindClose(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) { + r1, _, e1 := syscall.Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetCurrentDirectory(path *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) { + r1, _, e1 := syscall.Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func RemoveDirectory(path *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeleteFile(path *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MoveFile(from *uint16, to *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetComputerName(buf *uint16, n *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nametype), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetEndOfFile(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetSystemTimeAsFileTime(time *Filetime) { + syscall.Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) + return +} + +func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0) + rc = uint32(r0) + if rc == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CancelIo(s Handle) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CancelIoEx(s Handle, o *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) { + var _p0 uint32 + if inheritHandle { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := syscall.Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid)) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func TerminateProcess(handle Handle, exitcode uint32) (err error) { + r1, _, e1 := syscall.Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetStartupInfo(startupInfo *StartupInfo) (err error) { + r1, _, e1 := syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCurrentProcess() (pseudoHandle Handle, err error) { + r0, _, e1 := syscall.Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0) + pseudoHandle = Handle(r0) + if pseudoHandle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) { + r1, _, e1 := syscall.Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { + var _p0 uint32 + if bInheritHandle { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) { + r0, _, e1 := syscall.Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0) + event = uint32(r0) + if event == 0xffffffff { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileType(filehandle Handle) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CryptReleaseContext(provhandle Handle, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { + r1, _, e1 := syscall.Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetEnvironmentStrings() (envs *uint16, err error) { + r0, _, e1 := syscall.Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0) + envs = (*uint16)(unsafe.Pointer(r0)) + if envs == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FreeEnvironmentStrings(envs *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { + r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) { + r1, _, e1 := syscall.Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileAttributes(name *uint16) (attrs uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + attrs = uint32(r0) + if attrs == INVALID_FILE_ATTRIBUTES { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetFileAttributes(name *uint16, attrs uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) { + r1, _, e1 := syscall.Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCommandLine() (cmd *uint16) { + r0, _, _ := syscall.Syscall(procGetCommandLineW.Addr(), 0, 0, 0, 0) + cmd = (*uint16)(unsafe.Pointer(r0)) + return +} + +func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) { + r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) + argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0)) + if argv == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func LocalFree(hmem Handle) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0) + handle = Handle(r0) + if handle != 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FlushFileBuffers(handle Handle) (err error) { + r1, _, e1 := syscall.Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name))) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) { + r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0) + addr = uintptr(r0) + if addr == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func UnmapViewOfFile(addr uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FlushViewOfFile(addr uintptr, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func VirtualLock(addr uintptr, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func VirtualUnlock(addr uintptr, length uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { + var _p0 uint32 + if watchSubTree { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) { + r0, _, e1 := syscall.Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0) + store = Handle(r0) + if store == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) { + r0, _, e1 := syscall.Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0) + context = (*CertContext)(unsafe.Pointer(r0)) + if context == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) { + r1, _, e1 := syscall.Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertCloseStore(store Handle, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) { + r1, _, e1 := syscall.Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertFreeCertificateChain(ctx *CertChainContext) { + syscall.Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + return +} + +func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) { + r0, _, e1 := syscall.Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen)) + context = (*CertContext)(unsafe.Pointer(r0)) + if context == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertFreeCertificateContext(ctx *CertContext) (err error) { + r1, _, e1 := syscall.Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) { + r1, _, e1 := syscall.Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) { + r0, _, _ := syscall.Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegCloseKey(key Handle) (regerrno error) { + r0, _, _ := syscall.Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) { + r0, _, _ := syscall.Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime))) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen))) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func getCurrentProcessId() (pid uint32) { + r0, _, _ := syscall.Syscall(procGetCurrentProcessId.Addr(), 0, 0, 0, 0) + pid = uint32(r0) + return +} + +func GetConsoleMode(console Handle, mode *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) { + r1, _, e1 := syscall.Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) { + r1, _, e1 := syscall.Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags)) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved)) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetCurrentThreadId() (id uint32) { + r0, _, _ := syscall.Syscall(procGetCurrentThreadId.Addr(), 0, 0, 0, 0) + id = uint32(r0) + return +} + +func CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0) + handle = Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetEvent(event Handle) (err error) { + r1, _, e1 := syscall.Syscall(procSetEvent.Addr(), 1, uintptr(event), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSAStartup(verreq uint32, data *WSAData) (sockerr error) { + r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) + if r0 != 0 { + sockerr = syscall.Errno(r0) + } + return +} + +func WSACleanup() (err error) { + r1, _, e1 := syscall.Syscall(procWSACleanup.Addr(), 0, 0, 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) { + r1, _, e1 := syscall.Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine)) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func socket(af int32, typ int32, protocol int32) (handle Handle, err error) { + r0, _, e1 := syscall.Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol)) + handle = Handle(r0) + if handle == InvalidHandle { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) { + r1, _, e1 := syscall.Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) { + r1, _, e1 := syscall.Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { + r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) { + r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func listen(s Handle, backlog int32) (err error) { + r1, _, e1 := syscall.Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func shutdown(s Handle, how int32) (err error) { + r1, _, e1 := syscall.Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Closesocket(s Handle) (err error) { + r1, _, e1 := syscall.Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) { + r1, _, e1 := syscall.Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) { + syscall.Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) + return +} + +func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) { + r1, _, e1 := syscall.Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetHostByName(name string) (h *Hostent, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(name) + if err != nil { + return + } + return _GetHostByName(_p0) +} + +func _GetHostByName(name *byte) (h *Hostent, err error) { + r0, _, e1 := syscall.Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + h = (*Hostent)(unsafe.Pointer(r0)) + if h == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetServByName(name string, proto string) (s *Servent, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(name) + if err != nil { + return + } + var _p1 *byte + _p1, err = syscall.BytePtrFromString(proto) + if err != nil { + return + } + return _GetServByName(_p0, _p1) +} + +func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { + r0, _, e1 := syscall.Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0) + s = (*Servent)(unsafe.Pointer(r0)) + if s == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func Ntohs(netshort uint16) (u uint16) { + r0, _, _ := syscall.Syscall(procntohs.Addr(), 1, uintptr(netshort), 0, 0) + u = uint16(r0) + return +} + +func GetProtoByName(name string) (p *Protoent, err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(name) + if err != nil { + return + } + return _GetProtoByName(_p0) +} + +func _GetProtoByName(name *byte) (p *Protoent, err error) { + r0, _, e1 := syscall.Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) + p = (*Protoent)(unsafe.Pointer(r0)) + if p == nil { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + var _p0 *uint16 + _p0, status = syscall.UTF16PtrFromString(name) + if status != nil { + return + } + return _DnsQuery(_p0, qtype, options, extra, qrs, pr) +} + +func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + r0, _, _ := syscall.Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + if r0 != 0 { + status = syscall.Errno(r0) + } + return +} + +func DnsRecordListFree(rl *DNSRecord, freetype uint32) { + syscall.Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) + return +} + +func DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) { + r0, _, _ := syscall.Syscall(procDnsNameCompare_W.Addr(), 2, uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2)), 0) + same = r0 != 0 + return +} + +func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) { + r0, _, _ := syscall.Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0) + if r0 != 0 { + sockerr = syscall.Errno(r0) + } + return +} + +func FreeAddrInfoW(addrinfo *AddrinfoW) { + syscall.Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0) + return +} + +func GetIfEntry(pIfRow *MibIfRow) (errcode error) { + r0, _, _ := syscall.Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) { + r0, _, _ := syscall.Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) { + r0, _, e1 := syscall.Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength))) + n = int32(r0) + if n == -1 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { + r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func GetACP() (acp uint32) { + r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) + acp = uint32(r0) + return +} + +func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) { + r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) + nwrite = int32(r0) + if nwrite == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) + if r1&0xff == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) { + r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) { + r0, _, _ := syscall.Syscall(procNetGetJoinInformation.Addr(), 3, uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType))) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func NetApiBufferFree(buf *byte) (neterr error) { + r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0) + if r0 != 0 { + neterr = syscall.Errno(r0) + } + return +} + +func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) { + r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetLengthSid(sid *SID) (len uint32) { + r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + len = uint32(r0) + return +} + +func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) { + r1, _, e1 := syscall.Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) { + r1, _, e1 := syscall.Syscall12(procAllocateAndInitializeSid.Addr(), 11, uintptr(unsafe.Pointer(identAuth)), uintptr(subAuth), uintptr(subAuth0), uintptr(subAuth1), uintptr(subAuth2), uintptr(subAuth3), uintptr(subAuth4), uintptr(subAuth5), uintptr(subAuth6), uintptr(subAuth7), uintptr(unsafe.Pointer(sid)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func FreeSid(sid *SID) (err error) { + r1, _, e1 := syscall.Syscall(procFreeSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) + if r1 != 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) { + r0, _, _ := syscall.Syscall(procEqualSid.Addr(), 2, uintptr(unsafe.Pointer(sid1)), uintptr(unsafe.Pointer(sid2)), 0) + isEqual = r0 != 0 + return +} + +func OpenProcessToken(h Handle, access uint32, token *Token) (err error) { + r1, _, e1 := syscall.Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/golang.org/x/sys/windows/ztypes_windows.go b/vendor/golang.org/x/sys/windows/ztypes_windows.go new file mode 100644 index 0000000..1fe19d1 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/ztypes_windows.go @@ -0,0 +1,1242 @@ +// 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 windows + +import "syscall" + +const ( + // Windows errors. + ERROR_FILE_NOT_FOUND syscall.Errno = 2 + ERROR_PATH_NOT_FOUND syscall.Errno = 3 + ERROR_ACCESS_DENIED syscall.Errno = 5 + ERROR_NO_MORE_FILES syscall.Errno = 18 + ERROR_HANDLE_EOF syscall.Errno = 38 + ERROR_NETNAME_DELETED syscall.Errno = 64 + ERROR_FILE_EXISTS syscall.Errno = 80 + ERROR_BROKEN_PIPE syscall.Errno = 109 + ERROR_BUFFER_OVERFLOW syscall.Errno = 111 + ERROR_INSUFFICIENT_BUFFER syscall.Errno = 122 + ERROR_MOD_NOT_FOUND syscall.Errno = 126 + ERROR_PROC_NOT_FOUND syscall.Errno = 127 + ERROR_ALREADY_EXISTS syscall.Errno = 183 + ERROR_ENVVAR_NOT_FOUND syscall.Errno = 203 + ERROR_MORE_DATA syscall.Errno = 234 + ERROR_OPERATION_ABORTED syscall.Errno = 995 + ERROR_IO_PENDING syscall.Errno = 997 + ERROR_SERVICE_SPECIFIC_ERROR syscall.Errno = 1066 + ERROR_NOT_FOUND syscall.Errno = 1168 + ERROR_PRIVILEGE_NOT_HELD syscall.Errno = 1314 + WSAEACCES syscall.Errno = 10013 + WSAECONNRESET syscall.Errno = 10054 +) + +const ( + // Invented values to support what package os expects. + O_RDONLY = 0x00000 + O_WRONLY = 0x00001 + O_RDWR = 0x00002 + O_CREAT = 0x00040 + O_EXCL = 0x00080 + O_NOCTTY = 0x00100 + O_TRUNC = 0x00200 + O_NONBLOCK = 0x00800 + O_APPEND = 0x00400 + O_SYNC = 0x01000 + O_ASYNC = 0x02000 + O_CLOEXEC = 0x80000 +) + +const ( + // More invented values for signals + SIGHUP = Signal(0x1) + SIGINT = Signal(0x2) + SIGQUIT = Signal(0x3) + SIGILL = Signal(0x4) + SIGTRAP = Signal(0x5) + SIGABRT = Signal(0x6) + SIGBUS = Signal(0x7) + SIGFPE = Signal(0x8) + SIGKILL = Signal(0x9) + SIGSEGV = Signal(0xb) + SIGPIPE = Signal(0xd) + SIGALRM = Signal(0xe) + SIGTERM = Signal(0xf) +) + +var signals = [...]string{ + 1: "hangup", + 2: "interrupt", + 3: "quit", + 4: "illegal instruction", + 5: "trace/breakpoint trap", + 6: "aborted", + 7: "bus error", + 8: "floating point exception", + 9: "killed", + 10: "user defined signal 1", + 11: "segmentation fault", + 12: "user defined signal 2", + 13: "broken pipe", + 14: "alarm clock", + 15: "terminated", +} + +const ( + GENERIC_READ = 0x80000000 + GENERIC_WRITE = 0x40000000 + GENERIC_EXECUTE = 0x20000000 + GENERIC_ALL = 0x10000000 + + FILE_LIST_DIRECTORY = 0x00000001 + FILE_APPEND_DATA = 0x00000004 + FILE_WRITE_ATTRIBUTES = 0x00000100 + + FILE_SHARE_READ = 0x00000001 + FILE_SHARE_WRITE = 0x00000002 + FILE_SHARE_DELETE = 0x00000004 + FILE_ATTRIBUTE_READONLY = 0x00000001 + FILE_ATTRIBUTE_HIDDEN = 0x00000002 + FILE_ATTRIBUTE_SYSTEM = 0x00000004 + FILE_ATTRIBUTE_DIRECTORY = 0x00000010 + FILE_ATTRIBUTE_ARCHIVE = 0x00000020 + FILE_ATTRIBUTE_NORMAL = 0x00000080 + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 + + INVALID_FILE_ATTRIBUTES = 0xffffffff + + CREATE_NEW = 1 + CREATE_ALWAYS = 2 + OPEN_EXISTING = 3 + OPEN_ALWAYS = 4 + TRUNCATE_EXISTING = 5 + + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + FILE_FLAG_OVERLAPPED = 0x40000000 + + HANDLE_FLAG_INHERIT = 0x00000001 + STARTF_USESTDHANDLES = 0x00000100 + STARTF_USESHOWWINDOW = 0x00000001 + DUPLICATE_CLOSE_SOURCE = 0x00000001 + DUPLICATE_SAME_ACCESS = 0x00000002 + + STD_INPUT_HANDLE = -10 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + + FILE_BEGIN = 0 + FILE_CURRENT = 1 + FILE_END = 2 + + LANG_ENGLISH = 0x09 + SUBLANG_ENGLISH_US = 0x01 + + FORMAT_MESSAGE_ALLOCATE_BUFFER = 256 + FORMAT_MESSAGE_IGNORE_INSERTS = 512 + FORMAT_MESSAGE_FROM_STRING = 1024 + FORMAT_MESSAGE_FROM_HMODULE = 2048 + FORMAT_MESSAGE_FROM_SYSTEM = 4096 + FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192 + FORMAT_MESSAGE_MAX_WIDTH_MASK = 255 + + MAX_PATH = 260 + MAX_LONG_PATH = 32768 + + MAX_COMPUTERNAME_LENGTH = 15 + + TIME_ZONE_ID_UNKNOWN = 0 + TIME_ZONE_ID_STANDARD = 1 + + TIME_ZONE_ID_DAYLIGHT = 2 + IGNORE = 0 + INFINITE = 0xffffffff + + WAIT_TIMEOUT = 258 + WAIT_ABANDONED = 0x00000080 + WAIT_OBJECT_0 = 0x00000000 + WAIT_FAILED = 0xFFFFFFFF + + CREATE_NEW_PROCESS_GROUP = 0x00000200 + CREATE_UNICODE_ENVIRONMENT = 0x00000400 + + PROCESS_TERMINATE = 1 + PROCESS_QUERY_INFORMATION = 0x00000400 + SYNCHRONIZE = 0x00100000 + + PAGE_READONLY = 0x02 + PAGE_READWRITE = 0x04 + PAGE_WRITECOPY = 0x08 + PAGE_EXECUTE_READ = 0x20 + PAGE_EXECUTE_READWRITE = 0x40 + PAGE_EXECUTE_WRITECOPY = 0x80 + + FILE_MAP_COPY = 0x01 + FILE_MAP_WRITE = 0x02 + FILE_MAP_READ = 0x04 + FILE_MAP_EXECUTE = 0x20 + + CTRL_C_EVENT = 0 + CTRL_BREAK_EVENT = 1 + + // Windows reserves errors >= 1<<29 for application use. + APPLICATION_ERROR = 1 << 29 +) + +const ( + // flags for CreateToolhelp32Snapshot + TH32CS_SNAPHEAPLIST = 0x01 + TH32CS_SNAPPROCESS = 0x02 + TH32CS_SNAPTHREAD = 0x04 + TH32CS_SNAPMODULE = 0x08 + TH32CS_SNAPMODULE32 = 0x10 + TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD + TH32CS_INHERIT = 0x80000000 +) + +const ( + // filters for ReadDirectoryChangesW + FILE_NOTIFY_CHANGE_FILE_NAME = 0x001 + FILE_NOTIFY_CHANGE_DIR_NAME = 0x002 + FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x004 + FILE_NOTIFY_CHANGE_SIZE = 0x008 + FILE_NOTIFY_CHANGE_LAST_WRITE = 0x010 + FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020 + FILE_NOTIFY_CHANGE_CREATION = 0x040 + FILE_NOTIFY_CHANGE_SECURITY = 0x100 +) + +const ( + // do not reorder + FILE_ACTION_ADDED = iota + 1 + FILE_ACTION_REMOVED + FILE_ACTION_MODIFIED + FILE_ACTION_RENAMED_OLD_NAME + FILE_ACTION_RENAMED_NEW_NAME +) + +const ( + // wincrypt.h + PROV_RSA_FULL = 1 + PROV_RSA_SIG = 2 + PROV_DSS = 3 + PROV_FORTEZZA = 4 + PROV_MS_EXCHANGE = 5 + PROV_SSL = 6 + PROV_RSA_SCHANNEL = 12 + PROV_DSS_DH = 13 + PROV_EC_ECDSA_SIG = 14 + PROV_EC_ECNRA_SIG = 15 + PROV_EC_ECDSA_FULL = 16 + PROV_EC_ECNRA_FULL = 17 + PROV_DH_SCHANNEL = 18 + PROV_SPYRUS_LYNKS = 20 + PROV_RNG = 21 + PROV_INTEL_SEC = 22 + PROV_REPLACE_OWF = 23 + PROV_RSA_AES = 24 + CRYPT_VERIFYCONTEXT = 0xF0000000 + CRYPT_NEWKEYSET = 0x00000008 + CRYPT_DELETEKEYSET = 0x00000010 + CRYPT_MACHINE_KEYSET = 0x00000020 + CRYPT_SILENT = 0x00000040 + CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080 + + USAGE_MATCH_TYPE_AND = 0 + USAGE_MATCH_TYPE_OR = 1 + + X509_ASN_ENCODING = 0x00000001 + PKCS_7_ASN_ENCODING = 0x00010000 + + CERT_STORE_PROV_MEMORY = 2 + + CERT_STORE_ADD_ALWAYS = 4 + + CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004 + + CERT_TRUST_NO_ERROR = 0x00000000 + CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001 + CERT_TRUST_IS_REVOKED = 0x00000004 + CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008 + CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010 + CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020 + CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040 + CERT_TRUST_IS_CYCLIC = 0x00000080 + CERT_TRUST_INVALID_EXTENSION = 0x00000100 + CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200 + CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400 + CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800 + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000 + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000 + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000 + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000 + CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000 + CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000 + CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000 + CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000 + + CERT_CHAIN_POLICY_BASE = 1 + CERT_CHAIN_POLICY_AUTHENTICODE = 2 + CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3 + CERT_CHAIN_POLICY_SSL = 4 + CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5 + CERT_CHAIN_POLICY_NT_AUTH = 6 + CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7 + CERT_CHAIN_POLICY_EV = 8 + + CERT_E_EXPIRED = 0x800B0101 + CERT_E_ROLE = 0x800B0103 + CERT_E_PURPOSE = 0x800B0106 + CERT_E_UNTRUSTEDROOT = 0x800B0109 + CERT_E_CN_NO_MATCH = 0x800B010F + + AUTHTYPE_CLIENT = 1 + AUTHTYPE_SERVER = 2 +) + +var ( + OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00") + OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00") + OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00") +) + +// Invented values to support what package os expects. +type Timeval struct { + Sec int32 + Usec int32 +} + +func (tv *Timeval) Nanoseconds() int64 { + return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3 +} + +func NsecToTimeval(nsec int64) (tv Timeval) { + tv.Sec = int32(nsec / 1e9) + tv.Usec = int32(nsec % 1e9 / 1e3) + return +} + +type SecurityAttributes struct { + Length uint32 + SecurityDescriptor uintptr + InheritHandle uint32 +} + +type Overlapped struct { + Internal uintptr + InternalHigh uintptr + Offset uint32 + OffsetHigh uint32 + HEvent Handle +} + +type FileNotifyInformation struct { + NextEntryOffset uint32 + Action uint32 + FileNameLength uint32 + FileName uint16 +} + +type Filetime struct { + LowDateTime uint32 + HighDateTime uint32 +} + +// Nanoseconds returns Filetime ft in nanoseconds +// since Epoch (00:00:00 UTC, January 1, 1970). +func (ft *Filetime) Nanoseconds() int64 { + // 100-nanosecond intervals since January 1, 1601 + nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) + // change starting time to the Epoch (00:00:00 UTC, January 1, 1970) + nsec -= 116444736000000000 + // convert into nanoseconds + nsec *= 100 + return nsec +} + +func NsecToFiletime(nsec int64) (ft Filetime) { + // convert into 100-nanosecond + nsec /= 100 + // change starting time to January 1, 1601 + nsec += 116444736000000000 + // split into high / low + ft.LowDateTime = uint32(nsec & 0xffffffff) + ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff) + return ft +} + +type Win32finddata struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + Reserved0 uint32 + Reserved1 uint32 + FileName [MAX_PATH - 1]uint16 + AlternateFileName [13]uint16 +} + +// This is the actual system call structure. +// Win32finddata is what we committed to in Go 1. +type win32finddata1 struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 + Reserved0 uint32 + Reserved1 uint32 + FileName [MAX_PATH]uint16 + AlternateFileName [14]uint16 +} + +func copyFindData(dst *Win32finddata, src *win32finddata1) { + dst.FileAttributes = src.FileAttributes + dst.CreationTime = src.CreationTime + dst.LastAccessTime = src.LastAccessTime + dst.LastWriteTime = src.LastWriteTime + dst.FileSizeHigh = src.FileSizeHigh + dst.FileSizeLow = src.FileSizeLow + dst.Reserved0 = src.Reserved0 + dst.Reserved1 = src.Reserved1 + + // The src is 1 element bigger than dst, but it must be NUL. + copy(dst.FileName[:], src.FileName[:]) + copy(dst.AlternateFileName[:], src.AlternateFileName[:]) +} + +type ByHandleFileInformation struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + VolumeSerialNumber uint32 + FileSizeHigh uint32 + FileSizeLow uint32 + NumberOfLinks uint32 + FileIndexHigh uint32 + FileIndexLow uint32 +} + +const ( + GetFileExInfoStandard = 0 + GetFileExMaxInfoLevel = 1 +) + +type Win32FileAttributeData struct { + FileAttributes uint32 + CreationTime Filetime + LastAccessTime Filetime + LastWriteTime Filetime + FileSizeHigh uint32 + FileSizeLow uint32 +} + +// ShowWindow constants +const ( + // winuser.h + SW_HIDE = 0 + SW_NORMAL = 1 + SW_SHOWNORMAL = 1 + SW_SHOWMINIMIZED = 2 + SW_SHOWMAXIMIZED = 3 + SW_MAXIMIZE = 3 + SW_SHOWNOACTIVATE = 4 + SW_SHOW = 5 + SW_MINIMIZE = 6 + SW_SHOWMINNOACTIVE = 7 + SW_SHOWNA = 8 + SW_RESTORE = 9 + SW_SHOWDEFAULT = 10 + SW_FORCEMINIMIZE = 11 +) + +type StartupInfo struct { + Cb uint32 + _ *uint16 + Desktop *uint16 + Title *uint16 + X uint32 + Y uint32 + XSize uint32 + YSize uint32 + XCountChars uint32 + YCountChars uint32 + FillAttribute uint32 + Flags uint32 + ShowWindow uint16 + _ uint16 + _ *byte + StdInput Handle + StdOutput Handle + StdErr Handle +} + +type ProcessInformation struct { + Process Handle + Thread Handle + ProcessId uint32 + ThreadId uint32 +} + +type ProcessEntry32 struct { + Size uint32 + Usage uint32 + ProcessID uint32 + DefaultHeapID uintptr + ModuleID uint32 + Threads uint32 + ParentProcessID uint32 + PriClassBase int32 + Flags uint32 + ExeFile [MAX_PATH]uint16 +} + +type Systemtime struct { + Year uint16 + Month uint16 + DayOfWeek uint16 + Day uint16 + Hour uint16 + Minute uint16 + Second uint16 + Milliseconds uint16 +} + +type Timezoneinformation struct { + Bias int32 + StandardName [32]uint16 + StandardDate Systemtime + StandardBias int32 + DaylightName [32]uint16 + DaylightDate Systemtime + DaylightBias int32 +} + +// Socket related. + +const ( + AF_UNSPEC = 0 + AF_UNIX = 1 + AF_INET = 2 + AF_INET6 = 23 + AF_NETBIOS = 17 + + SOCK_STREAM = 1 + SOCK_DGRAM = 2 + SOCK_RAW = 3 + SOCK_SEQPACKET = 5 + + IPPROTO_IP = 0 + IPPROTO_IPV6 = 0x29 + IPPROTO_TCP = 6 + IPPROTO_UDP = 17 + + SOL_SOCKET = 0xffff + SO_REUSEADDR = 4 + SO_KEEPALIVE = 8 + SO_DONTROUTE = 16 + SO_BROADCAST = 32 + SO_LINGER = 128 + SO_RCVBUF = 0x1002 + SO_SNDBUF = 0x1001 + SO_UPDATE_ACCEPT_CONTEXT = 0x700b + SO_UPDATE_CONNECT_CONTEXT = 0x7010 + + 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 + SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 + + // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 + + IP_TOS = 0x3 + IP_TTL = 0x4 + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_TTL = 0xa + IP_MULTICAST_LOOP = 0xb + IP_ADD_MEMBERSHIP = 0xc + IP_DROP_MEMBERSHIP = 0xd + + IPV6_V6ONLY = 0x1b + IPV6_UNICAST_HOPS = 0x4 + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_LOOP = 0xb + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + + SOMAXCONN = 0x7fffffff + + TCP_NODELAY = 1 + + SHUT_RD = 0 + SHUT_WR = 1 + SHUT_RDWR = 2 + + WSADESCRIPTION_LEN = 256 + WSASYS_STATUS_LEN = 128 +) + +type WSABuf struct { + Len uint32 + Buf *byte +} + +// Invented values to support what package os expects. +const ( + S_IFMT = 0x1f000 + 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_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXUSR = 0x40 +) + +const ( + FILE_TYPE_CHAR = 0x0002 + FILE_TYPE_DISK = 0x0001 + FILE_TYPE_PIPE = 0x0003 + FILE_TYPE_REMOTE = 0x8000 + FILE_TYPE_UNKNOWN = 0x0000 +) + +type Hostent struct { + Name *byte + Aliases **byte + AddrType uint16 + Length uint16 + AddrList **byte +} + +type Protoent struct { + Name *byte + Aliases **byte + Proto uint16 +} + +const ( + DNS_TYPE_A = 0x0001 + DNS_TYPE_NS = 0x0002 + DNS_TYPE_MD = 0x0003 + DNS_TYPE_MF = 0x0004 + DNS_TYPE_CNAME = 0x0005 + DNS_TYPE_SOA = 0x0006 + DNS_TYPE_MB = 0x0007 + DNS_TYPE_MG = 0x0008 + DNS_TYPE_MR = 0x0009 + DNS_TYPE_NULL = 0x000a + DNS_TYPE_WKS = 0x000b + DNS_TYPE_PTR = 0x000c + DNS_TYPE_HINFO = 0x000d + DNS_TYPE_MINFO = 0x000e + DNS_TYPE_MX = 0x000f + DNS_TYPE_TEXT = 0x0010 + DNS_TYPE_RP = 0x0011 + DNS_TYPE_AFSDB = 0x0012 + DNS_TYPE_X25 = 0x0013 + DNS_TYPE_ISDN = 0x0014 + DNS_TYPE_RT = 0x0015 + DNS_TYPE_NSAP = 0x0016 + DNS_TYPE_NSAPPTR = 0x0017 + DNS_TYPE_SIG = 0x0018 + DNS_TYPE_KEY = 0x0019 + DNS_TYPE_PX = 0x001a + DNS_TYPE_GPOS = 0x001b + DNS_TYPE_AAAA = 0x001c + DNS_TYPE_LOC = 0x001d + DNS_TYPE_NXT = 0x001e + DNS_TYPE_EID = 0x001f + DNS_TYPE_NIMLOC = 0x0020 + DNS_TYPE_SRV = 0x0021 + DNS_TYPE_ATMA = 0x0022 + DNS_TYPE_NAPTR = 0x0023 + DNS_TYPE_KX = 0x0024 + DNS_TYPE_CERT = 0x0025 + DNS_TYPE_A6 = 0x0026 + DNS_TYPE_DNAME = 0x0027 + DNS_TYPE_SINK = 0x0028 + DNS_TYPE_OPT = 0x0029 + DNS_TYPE_DS = 0x002B + DNS_TYPE_RRSIG = 0x002E + DNS_TYPE_NSEC = 0x002F + DNS_TYPE_DNSKEY = 0x0030 + DNS_TYPE_DHCID = 0x0031 + DNS_TYPE_UINFO = 0x0064 + DNS_TYPE_UID = 0x0065 + DNS_TYPE_GID = 0x0066 + DNS_TYPE_UNSPEC = 0x0067 + DNS_TYPE_ADDRS = 0x00f8 + DNS_TYPE_TKEY = 0x00f9 + DNS_TYPE_TSIG = 0x00fa + DNS_TYPE_IXFR = 0x00fb + DNS_TYPE_AXFR = 0x00fc + DNS_TYPE_MAILB = 0x00fd + DNS_TYPE_MAILA = 0x00fe + DNS_TYPE_ALL = 0x00ff + DNS_TYPE_ANY = 0x00ff + DNS_TYPE_WINS = 0xff01 + DNS_TYPE_WINSR = 0xff02 + DNS_TYPE_NBSTAT = 0xff01 +) + +const ( + DNS_INFO_NO_RECORDS = 0x251D +) + +const ( + // flags inside DNSRecord.Dw + DnsSectionQuestion = 0x0000 + DnsSectionAnswer = 0x0001 + DnsSectionAuthority = 0x0002 + DnsSectionAdditional = 0x0003 +) + +type DNSSRVData struct { + Target *uint16 + Priority uint16 + Weight uint16 + Port uint16 + Pad uint16 +} + +type DNSPTRData struct { + Host *uint16 +} + +type DNSMXData struct { + NameExchange *uint16 + Preference uint16 + Pad uint16 +} + +type DNSTXTData struct { + StringCount uint16 + StringArray [1]*uint16 +} + +type DNSRecord struct { + Next *DNSRecord + Name *uint16 + Type uint16 + Length uint16 + Dw uint32 + Ttl uint32 + Reserved uint32 + Data [40]byte +} + +const ( + TF_DISCONNECT = 1 + TF_REUSE_SOCKET = 2 + TF_WRITE_BEHIND = 4 + TF_USE_DEFAULT_WORKER = 0 + TF_USE_SYSTEM_THREAD = 16 + TF_USE_KERNEL_APC = 32 +) + +type TransmitFileBuffers struct { + Head uintptr + HeadLength uint32 + Tail uintptr + TailLength uint32 +} + +const ( + IFF_UP = 1 + IFF_BROADCAST = 2 + IFF_LOOPBACK = 4 + IFF_POINTTOPOINT = 8 + IFF_MULTICAST = 16 +) + +const SIO_GET_INTERFACE_LIST = 0x4004747F + +// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old. +// will be fixed to change variable type as suitable. + +type SockaddrGen [24]byte + +type InterfaceInfo struct { + Flags uint32 + Address SockaddrGen + BroadcastAddress SockaddrGen + Netmask SockaddrGen +} + +type IpAddressString struct { + String [16]byte +} + +type IpMaskString IpAddressString + +type IpAddrString struct { + Next *IpAddrString + IpAddress IpAddressString + IpMask IpMaskString + Context uint32 +} + +const MAX_ADAPTER_NAME_LENGTH = 256 +const MAX_ADAPTER_DESCRIPTION_LENGTH = 128 +const MAX_ADAPTER_ADDRESS_LENGTH = 8 + +type IpAdapterInfo struct { + Next *IpAdapterInfo + ComboIndex uint32 + AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte + Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte + AddressLength uint32 + Address [MAX_ADAPTER_ADDRESS_LENGTH]byte + Index uint32 + Type uint32 + DhcpEnabled uint32 + CurrentIpAddress *IpAddrString + IpAddressList IpAddrString + GatewayList IpAddrString + DhcpServer IpAddrString + HaveWins bool + PrimaryWinsServer IpAddrString + SecondaryWinsServer IpAddrString + LeaseObtained int64 + LeaseExpires int64 +} + +const MAXLEN_PHYSADDR = 8 +const MAX_INTERFACE_NAME_LEN = 256 +const MAXLEN_IFDESCR = 256 + +type MibIfRow struct { + Name [MAX_INTERFACE_NAME_LEN]uint16 + Index uint32 + Type uint32 + Mtu uint32 + Speed uint32 + PhysAddrLen uint32 + PhysAddr [MAXLEN_PHYSADDR]byte + AdminStatus uint32 + OperStatus uint32 + LastChange uint32 + InOctets uint32 + InUcastPkts uint32 + InNUcastPkts uint32 + InDiscards uint32 + InErrors uint32 + InUnknownProtos uint32 + OutOctets uint32 + OutUcastPkts uint32 + OutNUcastPkts uint32 + OutDiscards uint32 + OutErrors uint32 + OutQLen uint32 + DescrLen uint32 + Descr [MAXLEN_IFDESCR]byte +} + +type CertContext struct { + EncodingType uint32 + EncodedCert *byte + Length uint32 + CertInfo uintptr + Store Handle +} + +type CertChainContext struct { + Size uint32 + TrustStatus CertTrustStatus + ChainCount uint32 + Chains **CertSimpleChain + LowerQualityChainCount uint32 + LowerQualityChains **CertChainContext + HasRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 +} + +type CertSimpleChain struct { + Size uint32 + TrustStatus CertTrustStatus + NumElements uint32 + Elements **CertChainElement + TrustListInfo uintptr + HasRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 +} + +type CertChainElement struct { + Size uint32 + CertContext *CertContext + TrustStatus CertTrustStatus + RevocationInfo *CertRevocationInfo + IssuanceUsage *CertEnhKeyUsage + ApplicationUsage *CertEnhKeyUsage + ExtendedErrorInfo *uint16 +} + +type CertRevocationInfo struct { + Size uint32 + RevocationResult uint32 + RevocationOid *byte + OidSpecificInfo uintptr + HasFreshnessTime uint32 + FreshnessTime uint32 + CrlInfo uintptr // *CertRevocationCrlInfo +} + +type CertTrustStatus struct { + ErrorStatus uint32 + InfoStatus uint32 +} + +type CertUsageMatch struct { + Type uint32 + Usage CertEnhKeyUsage +} + +type CertEnhKeyUsage struct { + Length uint32 + UsageIdentifiers **byte +} + +type CertChainPara struct { + Size uint32 + RequestedUsage CertUsageMatch + RequstedIssuancePolicy CertUsageMatch + URLRetrievalTimeout uint32 + CheckRevocationFreshnessTime uint32 + RevocationFreshnessTime uint32 + CacheResync *Filetime +} + +type CertChainPolicyPara struct { + Size uint32 + Flags uint32 + ExtraPolicyPara uintptr +} + +type SSLExtraCertChainPolicyPara struct { + Size uint32 + AuthType uint32 + Checks uint32 + ServerName *uint16 +} + +type CertChainPolicyStatus struct { + Size uint32 + Error uint32 + ChainIndex uint32 + ElementIndex uint32 + ExtraPolicyStatus uintptr +} + +const ( + // do not reorder + HKEY_CLASSES_ROOT = 0x80000000 + iota + HKEY_CURRENT_USER + HKEY_LOCAL_MACHINE + HKEY_USERS + HKEY_PERFORMANCE_DATA + HKEY_CURRENT_CONFIG + HKEY_DYN_DATA + + KEY_QUERY_VALUE = 1 + KEY_SET_VALUE = 2 + KEY_CREATE_SUB_KEY = 4 + KEY_ENUMERATE_SUB_KEYS = 8 + KEY_NOTIFY = 16 + KEY_CREATE_LINK = 32 + KEY_WRITE = 0x20006 + KEY_EXECUTE = 0x20019 + KEY_READ = 0x20019 + KEY_WOW64_64KEY = 0x0100 + KEY_WOW64_32KEY = 0x0200 + KEY_ALL_ACCESS = 0xf003f +) + +const ( + // do not reorder + REG_NONE = iota + REG_SZ + REG_EXPAND_SZ + REG_BINARY + REG_DWORD_LITTLE_ENDIAN + REG_DWORD_BIG_ENDIAN + REG_LINK + REG_MULTI_SZ + REG_RESOURCE_LIST + REG_FULL_RESOURCE_DESCRIPTOR + REG_RESOURCE_REQUIREMENTS_LIST + REG_QWORD_LITTLE_ENDIAN + REG_DWORD = REG_DWORD_LITTLE_ENDIAN + REG_QWORD = REG_QWORD_LITTLE_ENDIAN +) + +type AddrinfoW struct { + Flags int32 + Family int32 + Socktype int32 + Protocol int32 + Addrlen uintptr + Canonname *uint16 + Addr uintptr + Next *AddrinfoW +} + +const ( + AI_PASSIVE = 1 + AI_CANONNAME = 2 + AI_NUMERICHOST = 4 +) + +type GUID struct { + Data1 uint32 + Data2 uint16 + Data3 uint16 + Data4 [8]byte +} + +var WSAID_CONNECTEX = GUID{ + 0x25a207b9, + 0xddf3, + 0x4660, + [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}, +} + +const ( + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + FILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +const ( + WSAPROTOCOL_LEN = 255 + MAX_PROTOCOL_CHAIN = 7 + BASE_PROTOCOL = 1 + LAYERED_PROTOCOL = 0 + + XP1_CONNECTIONLESS = 0x00000001 + XP1_GUARANTEED_DELIVERY = 0x00000002 + XP1_GUARANTEED_ORDER = 0x00000004 + XP1_MESSAGE_ORIENTED = 0x00000008 + XP1_PSEUDO_STREAM = 0x00000010 + XP1_GRACEFUL_CLOSE = 0x00000020 + XP1_EXPEDITED_DATA = 0x00000040 + XP1_CONNECT_DATA = 0x00000080 + XP1_DISCONNECT_DATA = 0x00000100 + XP1_SUPPORT_BROADCAST = 0x00000200 + XP1_SUPPORT_MULTIPOINT = 0x00000400 + XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800 + XP1_MULTIPOINT_DATA_PLANE = 0x00001000 + XP1_QOS_SUPPORTED = 0x00002000 + XP1_UNI_SEND = 0x00008000 + XP1_UNI_RECV = 0x00010000 + XP1_IFS_HANDLES = 0x00020000 + XP1_PARTIAL_MESSAGE = 0x00040000 + XP1_SAN_SUPPORT_SDP = 0x00080000 + + PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001 + PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002 + PFL_HIDDEN = 0x00000004 + PFL_MATCHES_PROTOCOL_ZERO = 0x00000008 + PFL_NETWORKDIRECT_PROVIDER = 0x00000010 +) + +type WSAProtocolInfo struct { + ServiceFlags1 uint32 + ServiceFlags2 uint32 + ServiceFlags3 uint32 + ServiceFlags4 uint32 + ProviderFlags uint32 + ProviderId GUID + CatalogEntryId uint32 + ProtocolChain WSAProtocolChain + Version int32 + AddressFamily int32 + MaxSockAddr int32 + MinSockAddr int32 + SocketType int32 + Protocol int32 + ProtocolMaxOffset int32 + NetworkByteOrder int32 + SecurityScheme int32 + MessageSize uint32 + ProviderReserved uint32 + ProtocolName [WSAPROTOCOL_LEN + 1]uint16 +} + +type WSAProtocolChain struct { + ChainLen int32 + ChainEntries [MAX_PROTOCOL_CHAIN]uint32 +} + +type TCPKeepalive struct { + OnOff uint32 + Time uint32 + Interval uint32 +} + +type symbolicLinkReparseBuffer struct { + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 + Flags uint32 + PathBuffer [1]uint16 +} + +type mountPointReparseBuffer struct { + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 + PathBuffer [1]uint16 +} + +type reparseDataBuffer struct { + ReparseTag uint32 + ReparseDataLength uint16 + Reserved uint16 + + // GenericReparseBuffer + reparseBuffer byte +} + +const ( + FSCTL_GET_REPARSE_POINT = 0x900A8 + MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024 + IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 + IO_REPARSE_TAG_SYMLINK = 0xA000000C + SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 +) + +const ( + ComputerNameNetBIOS = 0 + ComputerNameDnsHostname = 1 + ComputerNameDnsDomain = 2 + ComputerNameDnsFullyQualified = 3 + ComputerNamePhysicalNetBIOS = 4 + ComputerNamePhysicalDnsHostname = 5 + ComputerNamePhysicalDnsDomain = 6 + ComputerNamePhysicalDnsFullyQualified = 7 + ComputerNameMax = 8 +) + +const ( + MOVEFILE_REPLACE_EXISTING = 0x1 + MOVEFILE_COPY_ALLOWED = 0x2 + MOVEFILE_DELAY_UNTIL_REBOOT = 0x4 + MOVEFILE_WRITE_THROUGH = 0x8 + MOVEFILE_CREATE_HARDLINK = 0x10 + MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 +) + +const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 + +const ( + IF_TYPE_OTHER = 1 + IF_TYPE_ETHERNET_CSMACD = 6 + IF_TYPE_ISO88025_TOKENRING = 9 + IF_TYPE_PPP = 23 + IF_TYPE_SOFTWARE_LOOPBACK = 24 + IF_TYPE_ATM = 37 + IF_TYPE_IEEE80211 = 71 + IF_TYPE_TUNNEL = 131 + IF_TYPE_IEEE1394 = 144 +) + +type SocketAddress struct { + Sockaddr *syscall.RawSockaddrAny + SockaddrLength int32 +} + +type IpAdapterUnicastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterUnicastAddress + Address SocketAddress + PrefixOrigin int32 + SuffixOrigin int32 + DadState int32 + ValidLifetime uint32 + PreferredLifetime uint32 + LeaseLifetime uint32 + OnLinkPrefixLength uint8 +} + +type IpAdapterAnycastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterAnycastAddress + Address SocketAddress +} + +type IpAdapterMulticastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterMulticastAddress + Address SocketAddress +} + +type IpAdapterDnsServerAdapter struct { + Length uint32 + Reserved uint32 + Next *IpAdapterDnsServerAdapter + Address SocketAddress +} + +type IpAdapterPrefix struct { + Length uint32 + Flags uint32 + Next *IpAdapterPrefix + Address SocketAddress + PrefixLength uint32 +} + +type IpAdapterAddresses struct { + Length uint32 + IfIndex uint32 + Next *IpAdapterAddresses + AdapterName *byte + FirstUnicastAddress *IpAdapterUnicastAddress + FirstAnycastAddress *IpAdapterAnycastAddress + FirstMulticastAddress *IpAdapterMulticastAddress + FirstDnsServerAddress *IpAdapterDnsServerAdapter + DnsSuffix *uint16 + Description *uint16 + FriendlyName *uint16 + PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte + PhysicalAddressLength uint32 + Flags uint32 + Mtu uint32 + IfType uint32 + OperStatus uint32 + Ipv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *IpAdapterPrefix + /* more fields might be present here. */ +} + +const ( + IfOperStatusUp = 1 + IfOperStatusDown = 2 + IfOperStatusTesting = 3 + IfOperStatusUnknown = 4 + IfOperStatusDormant = 5 + IfOperStatusNotPresent = 6 + IfOperStatusLowerLayerDown = 7 +) diff --git a/vendor/golang.org/x/sys/windows/ztypes_windows_386.go b/vendor/golang.org/x/sys/windows/ztypes_windows_386.go new file mode 100644 index 0000000..10f33be --- /dev/null +++ b/vendor/golang.org/x/sys/windows/ztypes_windows_386.go @@ -0,0 +1,22 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +type WSAData struct { + Version uint16 + HighVersion uint16 + Description [WSADESCRIPTION_LEN + 1]byte + SystemStatus [WSASYS_STATUS_LEN + 1]byte + MaxSockets uint16 + MaxUdpDg uint16 + VendorInfo *byte +} + +type Servent struct { + Name *byte + Aliases **byte + Port uint16 + Proto *byte +} diff --git a/vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go b/vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go new file mode 100644 index 0000000..3f272c2 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go @@ -0,0 +1,22 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +type WSAData struct { + Version uint16 + HighVersion uint16 + MaxSockets uint16 + MaxUdpDg uint16 + VendorInfo *byte + Description [WSADESCRIPTION_LEN + 1]byte + SystemStatus [WSASYS_STATUS_LEN + 1]byte +} + +type Servent struct { + Name *byte + Aliases **byte + Proto *byte + Port uint16 +} diff --git a/vendor/rsc.io/x86/LICENSE b/vendor/rsc.io/x86/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/rsc.io/x86/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/rsc.io/x86/x86asm/Makefile b/vendor/rsc.io/x86/x86asm/Makefile new file mode 100644 index 0000000..9eb4557 --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/Makefile @@ -0,0 +1,3 @@ +tables.go: ../x86map/map.go ../x86.csv + go run ../x86map/map.go -fmt=decoder ../x86.csv >_tables.go && gofmt _tables.go >tables.go && rm _tables.go + diff --git a/vendor/rsc.io/x86/x86asm/decode.go b/vendor/rsc.io/x86/x86asm/decode.go new file mode 100644 index 0000000..d11514d --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/decode.go @@ -0,0 +1,1646 @@ +// 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 x86asm + +import ( + "encoding/binary" + "errors" + "fmt" + "runtime" +) + +// 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 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 decodeOp uint16 + +const ( + xFail decodeOp = iota // invalid instruction (return) + xMatch // completed match + xJump // jump to pc + + xCondByte // switch on instruction byte value + xCondSlashR // read and switch on instruction /r value + xCondPrefix // switch on presence of instruction prefix + xCondIs64 // switch on 64-bit processor mode + xCondDataSize // switch on operand size + xCondAddrSize // switch on address size + xCondIsMem // switch on memory vs register argument + + xSetOp // set instruction opcode + + xReadSlashR // read /r + xReadIb // read ib + xReadIw // read iw + xReadId // read id + xReadIo // read io + xReadCb // read cb + xReadCw // read cw + xReadCd // read cd + xReadCp // read cp + xReadCm // read cm + + xArg1 // arg 1 + xArg3 // arg 3 + xArgAL // arg AL + xArgAX // arg AX + xArgCL // arg CL + xArgCR0dashCR7 // arg CR0-CR7 + xArgCS // arg CS + xArgDR0dashDR7 // arg DR0-DR7 + xArgDS // arg DS + xArgDX // arg DX + xArgEAX // arg EAX + xArgEDX // arg EDX + xArgES // arg ES + xArgFS // arg FS + xArgGS // arg GS + xArgImm16 // arg imm16 + xArgImm32 // arg imm32 + xArgImm64 // arg imm64 + xArgImm8 // arg imm8 + xArgImm8u // arg imm8 but record as unsigned + xArgImm16u // arg imm8 but record as unsigned + xArgM // arg m + xArgM128 // arg m128 + xArgM1428byte // arg m14/28byte + xArgM16 // arg m16 + xArgM16and16 // arg m16&16 + xArgM16and32 // arg m16&32 + xArgM16and64 // arg m16&64 + xArgM16colon16 // arg m16:16 + xArgM16colon32 // arg m16:32 + xArgM16colon64 // arg m16:64 + xArgM16int // arg m16int + xArgM2byte // arg m2byte + xArgM32 // arg m32 + xArgM32and32 // arg m32&32 + xArgM32fp // arg m32fp + xArgM32int // arg m32int + xArgM512byte // arg m512byte + xArgM64 // arg m64 + xArgM64fp // arg m64fp + xArgM64int // arg m64int + xArgM8 // arg m8 + xArgM80bcd // arg m80bcd + xArgM80dec // arg m80dec + xArgM80fp // arg m80fp + xArgM94108byte // arg m94/108byte + xArgMm // arg mm + xArgMm1 // arg mm1 + xArgMm2 // arg mm2 + xArgMm2M64 // arg mm2/m64 + xArgMmM32 // arg mm/m32 + xArgMmM64 // arg mm/m64 + xArgMem // arg mem + xArgMoffs16 // arg moffs16 + xArgMoffs32 // arg moffs32 + xArgMoffs64 // arg moffs64 + xArgMoffs8 // arg moffs8 + xArgPtr16colon16 // arg ptr16:16 + xArgPtr16colon32 // arg ptr16:32 + xArgR16 // arg r16 + xArgR16op // arg r16 with +rw in opcode + xArgR32 // arg r32 + xArgR32M16 // arg r32/m16 + xArgR32M8 // arg r32/m8 + xArgR32op // arg r32 with +rd in opcode + xArgR64 // arg r64 + xArgR64M16 // arg r64/m16 + xArgR64op // arg r64 with +rd in opcode + xArgR8 // arg r8 + xArgR8op // arg r8 with +rb in opcode + xArgRAX // arg RAX + xArgRDX // arg RDX + xArgRM // arg r/m + xArgRM16 // arg r/m16 + xArgRM32 // arg r/m32 + xArgRM64 // arg r/m64 + xArgRM8 // arg r/m8 + xArgReg // arg reg + xArgRegM16 // arg reg/m16 + xArgRegM32 // arg reg/m32 + xArgRegM8 // arg reg/m8 + xArgRel16 // arg rel16 + xArgRel32 // arg rel32 + xArgRel8 // arg rel8 + xArgSS // arg SS + xArgST // arg ST, aka ST(0) + xArgSTi // arg ST(i) with +i in opcode + xArgSreg // arg Sreg + xArgTR0dashTR7 // arg TR0-TR7 + xArgXmm // arg xmm + xArgXMM0 // arg + xArgXmm1 // arg xmm1 + xArgXmm2 // arg xmm2 + xArgXmm2M128 // arg xmm2/m128 + xArgXmm2M16 // arg xmm2/m16 + xArgXmm2M32 // arg xmm2/m32 + xArgXmm2M64 // arg xmm2/m64 + xArgXmmM128 // arg xmm/m128 + xArgXmmM32 // arg xmm/m32 + xArgXmmM64 // arg xmm/m64 + xArgRmf16 // arg r/m16 but force mod=3 + xArgRmf32 // arg r/m32 but force mod=3 + 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 instPrefix(b byte, mode int) (Inst, error) { + // When tracing it is useful to see what called instPrefix to report an error. + if trace { + _, file, line, _ := runtime.Caller(1) + fmt.Printf("%s:%d\n", file, line) + } + p := Prefix(b) + switch p { + case PrefixDataSize: + if mode == 16 { + p = PrefixData32 + } else { + p = PrefixData16 + } + case PrefixAddrSize: + if mode == 32 { + p = PrefixAddr16 + } else { + p = PrefixAddr32 + } + } + // Note: using composite literal with Prefix key confuses 'bundle' tool. + inst := Inst{Len: 1} + inst.Prefix = 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 truncated(src []byte, mode int) (Inst, error) { + // return Inst{}, len(src), ErrTruncated + return instPrefix(src[0], mode) // too long +} + +// These are the errors returned by Decode. +var ( + ErrInvalidMode = errors.New("invalid x86 mode in Decode") + ErrTruncated = errors.New("truncated instruction") + 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 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 Decode(src []byte, mode int) (inst Inst, err error) { + return 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 decode1(src []byte, mode int, gnuCompat bool) (Inst, error) { + switch mode { + case 16, 32, 64: + // ok + // TODO(rsc): 64-bit mode not tested, probably not working. + default: + return Inst{}, 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 Prefix // rex byte if present (or 0) + rexUsed 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 Mem + haveMem bool + + // decoded SIB fields + haveSIB bool + sib int + scale int + index int + base int + displen int + dispoff int + + // decoded immediate values + imm int64 + imm8 int8 + immc int64 + immcpos int + + // output + opshift int + inst 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 := 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] |= PrefixIgnored + } + lockIndex = pos + case 0xF2, 0xF3: + if repIndex >= 0 { + inst.Prefix[repIndex] |= PrefixIgnored + } + repIndex = pos + + // Group 2 - segment override / branch hints + case 0x26, 0x2E, 0x36, 0x3E: + if mode == 64 { + p |= PrefixIgnored + break + } + fallthrough + case 0x64, 0x65: + if segIndex >= 0 { + inst.Prefix[segIndex] |= PrefixIgnored + } + segIndex = pos + + // Group 3 - operand size override + case 0x66: + if mode == 16 { + dataMode = 32 + p = PrefixData32 + } else { + dataMode = 16 + p = PrefixData16 + } + if dataSizeIndex >= 0 { + inst.Prefix[dataSizeIndex] |= PrefixIgnored + } + dataSizeIndex = pos + + // Group 4 - address size override + case 0x67: + if mode == 32 { + addrMode = 16 + p = PrefixAddr16 + } else { + addrMode = 32 + p = PrefixAddr32 + } + if addrSizeIndex >= 0 { + inst.Prefix[addrSizeIndex] |= PrefixIgnored + } + addrSizeIndex = pos + } + + if pos >= len(inst.Prefix) { + return instPrefix(src[0], mode) // too long + } + + inst.Prefix[pos] = p + } + + // Read REX prefix. + if pos < len(src) && mode == 64 && Prefix(src[pos]).IsREX() { + rex = Prefix(src[pos]) + rexIndex = pos + if pos >= len(inst.Prefix) { + return instPrefix(src[0], mode) // too long + } + inst.Prefix[pos] = rex + pos++ + if rex&PrefixREXW != 0 { + dataMode = 64 + if dataSizeIndex >= 0 { + inst.Prefix[dataSizeIndex] |= 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 decoderCover == nil { + decoderCover = make([]bool, len(decoder)) + } + + // Decode loop, executing decoder program. + var oldPC, prevPC int +Decode: + for pc := 1; ; { // TODO uint + oldPC = prevPC + prevPC = pc + if trace { + println("run", pc) + } + x := decoder[pc] + decoderCover[pc] = true + pc++ + + // Read and decode ModR/M if needed by opcode. + switch decodeOp(x) { + case xCondSlashR, xReadSlashR: + if haveModrm { + return Inst{Len: pos}, errInternal + } + haveModrm = true + if pos >= len(src) { + return 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&PrefixREXR != 0 { + rexUsed |= PrefixREXR + regop |= 8 + } + if addrMode == 16 { + // 16-bit modrm form + if mod != 3 { + haveMem = true + mem = 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 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 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 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&PrefixREXB != 0 { + rexUsed |= PrefixREXB + base |= 8 + } + if rex&PrefixREXX != 0 { + rexUsed |= PrefixREXX + index |= 8 + } + + mem.Scale = 1 << uint(scale) + if index == 4 { + // no mem.Index + } else { + mem.Index = baseRegForBits(addrMode) + Reg(index) + } + if base&7 == 5 && mod == 0 { + // no mem.Base + } else { + mem.Base = baseRegForBits(addrMode) + Reg(base) + } + } else { + if rex&PrefixREXB != 0 { + rexUsed |= PrefixREXB + rm |= 8 + } + if mod == 0 && rm&7 == 5 || rm&7 == 4 { + // base omitted + } else if mod != 3 { + mem.Base = baseRegForBits(addrMode) + Reg(rm) + } + } + + // Consume disp32 if present. + if mod == 0 && (rm&7 == 5 || haveSIB && base&7 == 5) || mod == 2 { + if pos+4 > len(src) { + return truncated(src, mode) + } + dispoff = pos + displen = 4 + mem.Disp = int64(binary.LittleEndian.Uint32(src[pos:])) + pos += 4 + } + + // Consume disp8 if present. + if mod == 1 { + if pos >= len(src) { + return truncated(src, mode) + } + dispoff = pos + displen = 1 + 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 = EIP + } else { + mem.Base = RIP + } + } + } + + if segIndex >= 0 { + mem.Segment = prefixToSegment(inst.Prefix[segIndex]) + } + } + + // Execute single opcode. + switch decodeOp(x) { + default: + println("bad op", x, "at", pc-1, "from", oldPC) + return Inst{Len: pos}, errInternal + + case xFail: + inst.Op = 0 + break Decode + + case xMatch: + break Decode + + case xJump: + pc = int(decoder[pc]) + + // Conditional branches. + + case xCondByte: + if pos >= len(src) { + return truncated(src, mode) + } + b := src[pos] + n := int(decoder[pc]) + pc++ + for i := 0; i < n; i++ { + xb, xpc := decoder[pc], int(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 decodeOp(decoder[pc]) == xJump { + pc = int(decoder[pc+1]) + } + if decodeOp(decoder[pc]) == xFail { + pos++ + } + + case xCondIs64: + if mode == 64 { + pc = int(decoder[pc+1]) + } else { + pc = int(decoder[pc]) + } + + case xCondIsMem: + mem := haveMem + if !haveModrm { + if pos >= len(src) { + return instPrefix(src[0], mode) // too long + } + mem = src[pos]>>6 != 3 + } + if mem { + pc = int(decoder[pc+1]) + } else { + pc = int(decoder[pc]) + } + + case xCondDataSize: + switch dataMode { + case 16: + if dataSizeIndex >= 0 { + inst.Prefix[dataSizeIndex] |= PrefixImplicit + } + pc = int(decoder[pc]) + case 32: + if dataSizeIndex >= 0 { + inst.Prefix[dataSizeIndex] |= PrefixImplicit + } + pc = int(decoder[pc+1]) + case 64: + rexUsed |= PrefixREXW + pc = int(decoder[pc+2]) + } + + case xCondAddrSize: + switch addrMode { + case 16: + if addrSizeIndex >= 0 { + inst.Prefix[addrSizeIndex] |= PrefixImplicit + } + pc = int(decoder[pc]) + case 32: + if addrSizeIndex >= 0 { + inst.Prefix[addrSizeIndex] |= PrefixImplicit + } + pc = int(decoder[pc+1]) + case 64: + pc = int(decoder[pc+2]) + } + + case 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(decoder[pc]) + pc++ + sawF3 := false + for j := 0; j < n; j++ { + prefix := Prefix(decoder[pc+2*j]) + if prefix.IsREX() { + rexUsed |= prefix + if rex&prefix == prefix { + pc = int(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 PrefixLOCK: + if lockIndex >= 0 { + inst.Prefix[lockIndex] |= PrefixImplicit + ok = true + } + case PrefixREP, PrefixREPN: + if repIndex >= 0 && inst.Prefix[repIndex]&0xFF == prefix { + inst.Prefix[repIndex] |= PrefixImplicit + ok = true + } + if gnuCompat && !ok && prefix == 0xF3 && repIndex >= 0 && (j+1 >= n || 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] |= 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] |= PrefixImplicit + ok = true + } + } + } + case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS: + if segIndex >= 0 && inst.Prefix[segIndex]&0xFF == prefix { + inst.Prefix[segIndex] |= PrefixImplicit + ok = true + } + case 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] |= PrefixImplicit + ok = true + } + case PrefixAddrSize: + if addrSizeIndex >= 0 { + inst.Prefix[addrSizeIndex] |= PrefixImplicit + ok = true + } + } + } + if ok { + pc = int(decoder[pc+2*j+1]) + continue Decode + } + } + inst.Op = 0 + break Decode + + case xCondSlashR: + pc = int(decoder[pc+regop&7]) + + // Input. + + case xReadSlashR: + // done above + + case xReadIb: + if pos >= len(src) { + return truncated(src, mode) + } + imm8 = int8(src[pos]) + pos++ + + case xReadIw: + if pos+2 > len(src) { + return truncated(src, mode) + } + imm = int64(binary.LittleEndian.Uint16(src[pos:])) + pos += 2 + + case xReadId: + if pos+4 > len(src) { + return truncated(src, mode) + } + imm = int64(binary.LittleEndian.Uint32(src[pos:])) + pos += 4 + + case xReadIo: + if pos+8 > len(src) { + return truncated(src, mode) + } + imm = int64(binary.LittleEndian.Uint64(src[pos:])) + pos += 8 + + case xReadCb: + if pos >= len(src) { + return truncated(src, mode) + } + immcpos = pos + immc = int64(src[pos]) + pos++ + + case xReadCw: + if pos+2 > len(src) { + return truncated(src, mode) + } + immcpos = pos + immc = int64(binary.LittleEndian.Uint16(src[pos:])) + pos += 2 + + case xReadCm: + immcpos = pos + if addrMode == 16 { + if pos+2 > len(src) { + return truncated(src, mode) + } + immc = int64(binary.LittleEndian.Uint16(src[pos:])) + pos += 2 + } else if addrMode == 32 { + if pos+4 > len(src) { + return truncated(src, mode) + } + immc = int64(binary.LittleEndian.Uint32(src[pos:])) + pos += 4 + } else { + if pos+8 > len(src) { + return truncated(src, mode) + } + immc = int64(binary.LittleEndian.Uint64(src[pos:])) + pos += 8 + } + case xReadCd: + immcpos = pos + if pos+4 > len(src) { + return truncated(src, mode) + } + immc = int64(binary.LittleEndian.Uint32(src[pos:])) + pos += 4 + + case xReadCp: + immcpos = pos + if pos+6 > len(src) { + return 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 xSetOp: + inst.Op = Op(decoder[pc]) + pc++ + + case xArg1, + xArg3, + xArgAL, + xArgAX, + xArgCL, + xArgCS, + xArgDS, + xArgDX, + xArgEAX, + xArgEDX, + xArgES, + xArgFS, + xArgGS, + xArgRAX, + xArgRDX, + xArgSS, + xArgST, + xArgXMM0: + inst.Args[narg] = fixedArg[x] + narg++ + + case xArgImm8: + inst.Args[narg] = Imm(imm8) + narg++ + + case xArgImm8u: + inst.Args[narg] = Imm(uint8(imm8)) + narg++ + + case xArgImm16: + inst.Args[narg] = Imm(int16(imm)) + narg++ + + case xArgImm16u: + inst.Args[narg] = Imm(uint16(imm)) + narg++ + + case xArgImm32: + inst.Args[narg] = Imm(int32(imm)) + narg++ + + case xArgImm64: + inst.Args[narg] = Imm(imm) + narg++ + + case xArgM, + xArgM128, + xArgM1428byte, + xArgM16, + xArgM16and16, + xArgM16and32, + xArgM16and64, + xArgM16colon16, + xArgM16colon32, + xArgM16colon64, + xArgM16int, + xArgM2byte, + xArgM32, + xArgM32and32, + xArgM32fp, + xArgM32int, + xArgM512byte, + xArgM64, + xArgM64fp, + xArgM64int, + xArgM8, + xArgM80bcd, + xArgM80dec, + xArgM80fp, + xArgM94108byte, + xArgMem: + if !haveMem { + inst.Op = 0 + break Decode + } + inst.Args[narg] = mem + inst.MemBytes = int(memBytes[decodeOp(x)]) + if mem.Base == RIP { + inst.PCRel = displen + inst.PCRelOff = dispoff + } + narg++ + + case xArgPtr16colon16: + inst.Args[narg] = Imm(immc >> 16) + inst.Args[narg+1] = Imm(immc & (1<<16 - 1)) + narg += 2 + + case xArgPtr16colon32: + inst.Args[narg] = Imm(immc >> 32) + inst.Args[narg+1] = Imm(immc & (1<<32 - 1)) + narg += 2 + + case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64: + // TODO(rsc): Can address be 64 bits? + mem = Mem{Disp: int64(immc)} + if segIndex >= 0 { + mem.Segment = prefixToSegment(inst.Prefix[segIndex]) + inst.Prefix[segIndex] |= PrefixImplicit + } + inst.Args[narg] = mem + inst.MemBytes = int(memBytes[decodeOp(x)]) + if mem.Base == RIP { + inst.PCRel = displen + inst.PCRelOff = dispoff + } + narg++ + + case xArgR8, xArgR16, xArgR32, xArgR64, xArgXmm, xArgXmm1, xArgDR0dashDR7: + base := baseReg[x] + index := Reg(regop) + if rex != 0 && base == AL && index >= 4 { + rexUsed |= PrefixREX + index -= 4 + base = SPB + } + inst.Args[narg] = base + index + narg++ + + case xArgMm, xArgMm1, xArgTR0dashTR7: + inst.Args[narg] = baseReg[x] + Reg(regop&7) + narg++ + + case 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] |= PrefixImplicit + regop += 8 + } + inst.Args[narg] = CR0 + Reg(regop) + narg++ + + case xArgSreg: + regop &= 7 + if regop >= 6 { + inst.Op = 0 + break Decode + } + inst.Args[narg] = ES + Reg(regop) + narg++ + + case xArgRmf16, xArgRmf32, xArgRmf64: + base := baseReg[x] + index := Reg(modrm & 07) + if rex&PrefixREXB != 0 { + rexUsed |= PrefixREXB + index += 8 + } + inst.Args[narg] = base + index + narg++ + + case xArgR8op, xArgR16op, xArgR32op, xArgR64op, xArgSTi: + n := inst.Opcode >> uint(opshift+8) & 07 + base := baseReg[x] + index := Reg(n) + if rex&PrefixREXB != 0 && decodeOp(x) != xArgSTi { + rexUsed |= PrefixREXB + index += 8 + } + if rex != 0 && base == AL && index >= 4 { + rexUsed |= PrefixREX + index -= 4 + base = SPB + } + inst.Args[narg] = base + index + narg++ + + case xArgRM8, xArgRM16, xArgRM32, xArgRM64, xArgR32M16, xArgR32M8, xArgR64M16, + xArgMmM32, xArgMmM64, xArgMm2M64, + xArgXmm2M16, xArgXmm2M32, xArgXmm2M64, xArgXmmM64, xArgXmmM128, xArgXmmM32, xArgXmm2M128: + if haveMem { + inst.Args[narg] = mem + inst.MemBytes = int(memBytes[decodeOp(x)]) + if mem.Base == RIP { + inst.PCRel = displen + inst.PCRelOff = dispoff + } + } else { + base := baseReg[x] + index := Reg(rm) + switch decodeOp(x) { + case xArgMmM32, xArgMmM64, xArgMm2M64: + // There are only 8 MMX registers, so these ignore the REX.X bit. + index &= 7 + case xArgRM8: + if rex != 0 && index >= 4 { + rexUsed |= PrefixREX + index -= 4 + base = SPB + } + } + inst.Args[narg] = base + index + } + narg++ + + case xArgMm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag + if haveMem { + inst.Op = 0 + break Decode + } + inst.Args[narg] = baseReg[x] + Reg(rm&7) + narg++ + + case xArgXmm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag + if haveMem { + inst.Op = 0 + break Decode + } + inst.Args[narg] = baseReg[x] + Reg(rm) + narg++ + + case xArgRel8: + inst.PCRelOff = immcpos + inst.PCRel = 1 + inst.Args[narg] = Rel(int8(immc)) + narg++ + + case xArgRel16: + inst.PCRelOff = immcpos + inst.PCRel = 2 + inst.Args[narg] = Rel(int16(immc)) + narg++ + + case xArgRel32: + inst.PCRelOff = immcpos + inst.PCRel = 4 + inst.Args[narg] = Rel(int32(immc)) + narg++ + } + } + + if inst.Op == 0 { + // Invalid instruction. + if nprefix > 0 { + return instPrefix(src[0], mode) // invalid instruction + } + return Inst{Len: pos}, 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 == XCHG && inst.Opcode>>24 == 0x90 { + if inst.Args[0] == RAX || inst.Args[0] == EAX || inst.Args[0] == AX { + inst.Op = NOP + if dataSizeIndex >= 0 { + inst.Prefix[dataSizeIndex] &^= PrefixImplicit + } + inst.Args[0] = nil + inst.Args[1] = nil + } + if repIndex >= 0 && inst.Prefix[repIndex] == 0xF3 { + inst.Prefix[repIndex] |= PrefixImplicit + inst.Op = 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] |= PrefixImplicit + inst.Op = 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() Reg { + if segIndex >= 0 { + inst.Prefix[segIndex] |= PrefixImplicit + return prefixToSegment(inst.Prefix[segIndex]) + } + return 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 INSB, INSW, INSD: + inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX} + inst.Args[1] = DX + usedAddrSize = true + + case OUTSB, OUTSW, OUTSD: + inst.Args[0] = DX + inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX} + usedAddrSize = true + + case MOVSB, MOVSW, MOVSD, MOVSQ: + inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX} + inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX} + usedAddrSize = true + + case CMPSB, CMPSW, CMPSD, CMPSQ: + inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX} + inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX} + usedAddrSize = true + + case LODSB, LODSW, LODSD, LODSQ: + switch inst.Op { + case LODSB: + inst.Args[0] = AL + case LODSW: + inst.Args[0] = AX + case LODSD: + inst.Args[0] = EAX + case LODSQ: + inst.Args[0] = RAX + } + inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX} + usedAddrSize = true + + case STOSB, STOSW, STOSD, STOSQ: + inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX} + switch inst.Op { + case STOSB: + inst.Args[1] = AL + case STOSW: + inst.Args[1] = AX + case STOSD: + inst.Args[1] = EAX + case STOSQ: + inst.Args[1] = RAX + } + usedAddrSize = true + + case SCASB, SCASW, SCASD, SCASQ: + inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX} + switch inst.Op { + case SCASB: + inst.Args[0] = AL + case SCASW: + inst.Args[0] = AX + case SCASD: + inst.Args[0] = EAX + case SCASQ: + inst.Args[0] = RAX + } + usedAddrSize = true + + case XLATB: + inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + BX - 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] |= 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] |= 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 isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ { + PredictLoop: + for i := nprefix - 1; i >= 0; i-- { + p := inst.Prefix[i] + switch p & 0xFF { + case PrefixCS: + inst.Prefix[i] = PrefixPN + break PredictLoop + case PrefixDS: + inst.Prefix[i] = 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 isCondJmp[inst.Op] || inst.Op == JMP || inst.Op == CALL || inst.Op == RET { + for i := nprefix - 1; i >= 0; i-- { + p := inst.Prefix[i] + if p&^PrefixIgnored == PrefixREPN { + inst.Prefix[i] = 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]&PrefixImplicit == 0 { + switch inst.Op { + // TODO(rsc): Perhaps this instruction class should be derived from the CSV. + case ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG: + if isMem(inst.Args[0]) { + hasLock = true + break + } + fallthrough + default: + inst.Prefix[lockIndex] |= 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 isMem(inst.Args[0]) { + if inst.Op == XCHG { + hasLock = true + } + + for i := len(inst.Prefix) - 1; i >= 0; i-- { + p := inst.Prefix[i] &^ PrefixIgnored + switch p { + case PrefixREPN: + if hasLock { + inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXACQUIRE + } + + case PrefixREP: + if hasLock { + inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE + } + + if inst.Op == MOV { + op := (inst.Opcode >> 24) &^ 1 + if op == 0x88 || op == 0xC6 { + inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE + } + } + } + } + } + + // If REP is used on a non-REP-able instruction, mark the prefix as ignored. + if repIndex >= 0 { + switch inst.Prefix[repIndex] { + case PrefixREP, 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 INSB, INSW, INSD, + MOVSB, MOVSW, MOVSD, MOVSQ, + OUTSB, OUTSW, OUTSD, + LODSB, LODSW, LODSD, LODSQ, + CMPSB, CMPSW, CMPSD, CMPSQ, + SCASB, SCASW, SCASD, SCASQ, + STOSB, STOSW, STOSD, STOSQ: + // ok + default: + inst.Prefix[repIndex] |= PrefixIgnored + } + } + } + + // If REX was present, mark implicit if all the 1 bits were consumed. + if rexIndex >= 0 { + if rexUsed != 0 { + rexUsed |= PrefixREX + } + if rex&^rexUsed == 0 { + inst.Prefix[rexIndex] |= PrefixImplicit + } + } + + inst.DataSize = dataMode + inst.AddrSize = addrMode + inst.Mode = mode + inst.Len = pos + return inst, nil +} + +var errInternal = errors.New("internal error") + +// addr16 records the eight 16-bit addressing modes. +var addr16 = [8]Mem{ + {Base: BX, Scale: 1, Index: SI}, + {Base: BX, Scale: 1, Index: DI}, + {Base: BP, Scale: 1, Index: SI}, + {Base: BP, Scale: 1, Index: DI}, + {Base: SI}, + {Base: DI}, + {Base: BP}, + {Base: BX}, +} + +// baseReg returns the base register for a given register size in bits. +func baseRegForBits(bits int) Reg { + switch bits { + case 8: + return AL + case 16: + return AX + case 32: + return EAX + case 64: + return RAX + } + return 0 +} + +// baseReg records the base register for argument types that specify +// a range of registers indexed by op, regop, or rm. +var baseReg = [...]Reg{ + xArgDR0dashDR7: DR0, + xArgMm1: M0, + xArgMm2: M0, + xArgMm2M64: M0, + xArgMm: M0, + xArgMmM32: M0, + xArgMmM64: M0, + xArgR16: AX, + xArgR16op: AX, + xArgR32: EAX, + xArgR32M16: EAX, + xArgR32M8: EAX, + xArgR32op: EAX, + xArgR64: RAX, + xArgR64M16: RAX, + xArgR64op: RAX, + xArgR8: AL, + xArgR8op: AL, + xArgRM16: AX, + xArgRM32: EAX, + xArgRM64: RAX, + xArgRM8: AL, + xArgRmf16: AX, + xArgRmf32: EAX, + xArgRmf64: RAX, + xArgSTi: F0, + xArgTR0dashTR7: TR0, + xArgXmm1: X0, + xArgXmm2: X0, + xArgXmm2M128: X0, + xArgXmm2M16: X0, + xArgXmm2M32: X0, + xArgXmm2M64: X0, + xArgXmm: X0, + xArgXmmM128: X0, + xArgXmmM32: X0, + xArgXmmM64: X0, +} + +// prefixToSegment returns the segment register +// corresponding to a particular segment prefix. +func prefixToSegment(p Prefix) Reg { + switch p &^ PrefixImplicit { + case PrefixCS: + return CS + case PrefixDS: + return DS + case PrefixES: + return ES + case PrefixFS: + return FS + case PrefixGS: + return GS + case PrefixSS: + return SS + } + return 0 +} + +// fixedArg records the fixed arguments corresponding to the given bytecodes. +var fixedArg = [...]Arg{ + xArg1: Imm(1), + xArg3: Imm(3), + xArgAL: AL, + xArgAX: AX, + xArgDX: DX, + xArgEAX: EAX, + xArgEDX: EDX, + xArgRAX: RAX, + xArgRDX: RDX, + xArgCL: CL, + xArgCS: CS, + xArgDS: DS, + xArgES: ES, + xArgFS: FS, + xArgGS: GS, + xArgSS: SS, + xArgST: F0, + xArgXMM0: X0, +} + +// memBytes records the size of the memory pointed at +// by a memory argument of the given form. +var memBytes = [...]int8{ + xArgM128: 128 / 8, + xArgM16: 16 / 8, + xArgM16and16: (16 + 16) / 8, + xArgM16colon16: (16 + 16) / 8, + xArgM16colon32: (16 + 32) / 8, + xArgM16int: 16 / 8, + xArgM2byte: 2, + xArgM32: 32 / 8, + xArgM32and32: (32 + 32) / 8, + xArgM32fp: 32 / 8, + xArgM32int: 32 / 8, + xArgM64: 64 / 8, + xArgM64fp: 64 / 8, + xArgM64int: 64 / 8, + xArgMm2M64: 64 / 8, + xArgMmM32: 32 / 8, + xArgMmM64: 64 / 8, + xArgMoffs16: 16 / 8, + xArgMoffs32: 32 / 8, + xArgMoffs64: 64 / 8, + xArgMoffs8: 8 / 8, + xArgR32M16: 16 / 8, + xArgR32M8: 8 / 8, + xArgR64M16: 16 / 8, + xArgRM16: 16 / 8, + xArgRM32: 32 / 8, + xArgRM64: 64 / 8, + xArgRM8: 8 / 8, + xArgXmm2M128: 128 / 8, + xArgXmm2M16: 16 / 8, + xArgXmm2M32: 32 / 8, + xArgXmm2M64: 64 / 8, + xArgXmm: 128 / 8, + xArgXmmM128: 128 / 8, + xArgXmmM32: 32 / 8, + xArgXmmM64: 64 / 8, +} + +// isCondJmp records the conditional jumps. +var isCondJmp = [maxOp + 1]bool{ + JA: true, + JAE: true, + JB: true, + JBE: true, + JE: true, + JG: true, + JGE: true, + JL: true, + JLE: true, + JNE: true, + JNO: true, + JNP: true, + JNS: true, + JO: true, + JP: true, + JS: true, +} + +// isLoop records the loop operators. +var isLoop = [maxOp + 1]bool{ + LOOP: true, + LOOPE: true, + LOOPNE: true, + JECXZ: true, + JRCXZ: true, +} diff --git a/vendor/rsc.io/x86/x86asm/gnu.go b/vendor/rsc.io/x86/x86asm/gnu.go new file mode 100644 index 0000000..e2ff801 --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/gnu.go @@ -0,0 +1,926 @@ +// 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 + +import ( + "fmt" + "strings" +) + +// 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 GNUSyntax(inst 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 FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, 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].(Reg) + _, reg2 := inst.Args[1].(Reg) + if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) { + switch inst.Op { + case FDIV: + inst.Op = FDIVR + case FDIVR: + inst.Op = FDIV + case FSUB: + inst.Op = FSUBR + case FSUBR: + inst.Op = FSUB + case FDIVP: + inst.Op = FDIVRP + case FDIVRP: + inst.Op = FDIVP + case FSUBP: + inst.Op = FSUBRP + case FSUBRP: + inst.Op = FSUBP + } + } + + case 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 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] |= PrefixImplicit + } + case 0xF2: + inst.Prefix[i] &^= PrefixImplicit + } + } + inst.Op = MOVNTSS + } + } + + // Add implicit arguments. + switch inst.Op { + case MONITOR: + inst.Args[0] = EDX + inst.Args[1] = ECX + inst.Args[2] = EAX + if inst.AddrSize == 16 { + inst.Args[2] = AX + } + + case MWAIT: + if inst.Mode == 64 { + inst.Args[0] = RCX + inst.Args[1] = RAX + } else { + inst.Args[0] = ECX + inst.Args[1] = 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 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 countPrefix(&inst, 0xF2) > 1 { + unmarkImplicit(&inst, 0xF2) + 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. + unmarkImplicit(&inst, PrefixDataSize) + markLastImplicit(&inst, PrefixDataSize) + + case CVTSI2SD, CVTSI2SS: + if !isMem(inst.Args[1]) { + markLastImplicit(&inst, PrefixDataSize) + } + + case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI, + ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET, + POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN: + markLastImplicit(&inst, PrefixDataSize) + + case LOOP, LOOPE, LOOPNE, MONITOR: + markLastImplicit(&inst, PrefixAddrSize) + + case 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].(Reg) + src, _ := inst.Args[1].(Reg) + if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) { + unmarkImplicit(&inst, PrefixDataSize) + } + + case MOVDQU: + if countPrefix(&inst, 0xF3) > 1 { + unmarkImplicit(&inst, 0xF3) + markLastImplicit(&inst, 0xF3) + } + + case MOVQ2DQ: + markLastImplicit(&inst, PrefixDataSize) + + case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B: + if isMem(inst.Args[0]) { + unmarkImplicit(&inst, PrefixDataSize) + } + + case SYSEXIT: + unmarkImplicit(&inst, PrefixDataSize) + } + + if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ { + if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 { + for i, p := range inst.Prefix { + switch p & 0xFFF { + case PrefixPN, PrefixPT: + inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix + } + } + } + } + + // XACQUIRE/XRELEASE adjustment. + if inst.Op == 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] &^ PrefixIgnored { + case PrefixREPN: + haveREPN = true + case PrefixXRELEASE: + if haveREPN { + inst.Prefix[i] = 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] &^ PrefixIgnored { + case PrefixXRELEASE: + if !haveXR { + haveXR = true + } else { + inst.Prefix[i] = PrefixREP + } + + case PrefixXACQUIRE: + if !haveXA { + haveXA = true + } else { + inst.Prefix[i] = PrefixREPN + } + } + } + + // Determine opcode. + op := strings.ToLower(inst.Op.String()) + if alt := 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 Reg: + switch inst.Op { + case MOVSX, MOVZX: + continue + + case SHL, SHR, RCL, RCR, ROL, ROR, SAR: + if i == 1 { + // shift count does not tell us operand size + continue + } + + case CRC32: + // The source argument does tell us operand size, + // but libopcodes still always puts a suffix on crc32. + continue + + case PUSH, 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 ES <= a && a <= GS { + continue + } + + case CVTSI2SD, CVTSI2SS: + // The integer register argument takes priority. + if X0 <= a && a <= X15 { + continue + } + } + + if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 { + needSuffix = false + break SuffixLoop + } + } + } + + if needSuffix { + switch inst.Op { + case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ, + SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS, + SLDT, SMSW, STMXCSR, STR, VERR, VERW: + // For various reasons, libopcodes emits no suffix for these instructions. + + case CRC32: + op += byteSizeSuffix(argBytes(&inst, inst.Args[1])) + + case LGDT, LIDT, SGDT, SIDT: + op += byteSizeSuffix(inst.DataSize / 8) + + case MOVZX, MOVSX: + // Integer size conversions get two suffixes. + op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0])) + + case LOOP, LOOPE, LOOPNE: + // Add w suffix to indicate use of CX register instead of ECX. + if inst.AddrSize == 16 { + op += "w" + } + + case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, 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 { + markLastImplicit(&inst, PrefixDataSize) + op += "w" + } else if inst.Mode == 64 { + op += "q" + } + + case FRSTOR, FNSAVE, FNSTENV, FLDENV: + // Add s suffix to indicate shortened FPU state (I guess). + if inst.DataSize == 16 { + op += "s" + } + + case PUSH, POP: + if markLastImplicit(&inst, PrefixDataSize) { + op += byteSizeSuffix(inst.DataSize / 8) + } else if inst.Mode == 64 { + op += "q" + } else { + op += byteSizeSuffix(inst.MemBytes) + } + + default: + if isFloat(inst.Op) { + // I can't explain any of this, but it's what libopcodes does. + switch inst.MemBytes { + default: + if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) { + op += "t" + } + case 4: + if isFloatInt(inst.Op) { + op += "l" + } else { + op += "s" + } + case 8: + if isFloatInt(inst.Op) { + op += "ll" + } else { + op += "l" + } + } + break + } + + op += 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 INT: + if inst.Opcode>>24 == 0xCC { + inst.Args[0] = nil + op = "int3" + } + + case CMPPS, CMPPD, CMPSD_XMM, CMPSS: + imm, ok := inst.Args[2].(Imm) + if ok && 0 <= imm && imm < 8 { + inst.Args[2] = nil + op = cmppsOps[imm] + op[3:] + } + + case PCLMULQDQ: + imm, ok := inst.Args[2].(Imm) + if ok && imm&^0x11 == 0 { + inst.Args[2] = nil + op = pclmulqOps[(imm&0x10)>>3|(imm&1)] + } + + case XLATB: + if markLastImplicit(&inst, 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 MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD: + if i == 0 { + usedPrefixes = true // disable use of prefixes for first argument + } else { + usedPrefixes = false + } + } + if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 { + continue + } + args = append(args, 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 BOUND, LCALL, ENTER, 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 == PrefixDataSize && p&PrefixImplicit != 0 { + implicitData = true + } + } + for _, p := range inst.Prefix { + if p == 0 { + break + } + if p&PrefixImplicit != 0 { + continue + } + switch p &^ (PrefixIgnored | PrefixInvalid) { + default: + if p.IsREX() { + if p&0xFF == PrefixREX { + prefix += "rex " + } else { + prefix += "rex." + p.String()[4:] + " " + } + break + } + prefix += strings.ToLower(p.String()) + " " + + case PrefixPN: + op += ",pn" + continue + + case PrefixPT: + op += ",pt" + continue + + case PrefixAddrSize, PrefixAddr16, 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 countPrefix(&inst, PrefixAddrSize) > numAddr { + n = inst.Mode + } + prefix += fmt.Sprintf("addr%d ", n) + continue + + case PrefixData16, PrefixData32: + if implicitData && countPrefix(&inst, 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 countPrefix(&inst, 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 == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || 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 gnuArg(inst *Inst, x Arg, usedPrefixes *bool) string { + if x == nil { + return "" + } + switch x := x.(type) { + case Reg: + switch inst.Op { + case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI: + if inst.DataSize == 16 && EAX <= x && x <= R15L { + x -= EAX - AX + } + + case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD: + // DX is the port, but libopcodes prints it as if it were a memory reference. + if x == DX { + return "(%dx)" + } + } + return gccRegName[x] + case Mem: + seg := "" + var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool + switch x.Segment { + case CS: + haveCS = true + case DS: + haveDS = true + case ES: + haveES = true + case FS: + haveFS = true + case GS: + haveGS = true + case SS: + haveSS = true + } + switch inst.Op { + case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, 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] &^ PrefixIgnored + if p == 0 { + continue + } + switch p { + case PrefixCS: + if !haveCS { + haveCS = true + inst.Prefix[i] |= PrefixImplicit + } + case PrefixDS: + if !haveDS { + haveDS = true + inst.Prefix[i] |= PrefixImplicit + } + case PrefixES: + if !haveES { + haveES = true + inst.Prefix[i] |= PrefixImplicit + } + case PrefixFS: + if !haveFS { + haveFS = true + inst.Prefix[i] |= PrefixImplicit + } + case PrefixGS: + if !haveGS { + haveGS = true + inst.Prefix[i] |= PrefixImplicit + } + case PrefixSS: + if !haveSS { + haveSS = true + inst.Prefix[i] |= 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 == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) { + if x.Base == 0 { + return seg + disp + } + return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base]) + } + base := gccRegName[x.Base] + if x.Base == 0 { + base = "" + } + index := gccRegName[x.Index] + if x.Index == 0 { + if inst.AddrSize == 64 { + index = "%riz" + } else { + index = "%eiz" + } + } + if AX <= x.Base && x.Base <= 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 Rel: + return fmt.Sprintf(".%+#x", int32(x)) + case Imm: + if inst.Mode == 32 { + return fmt.Sprintf("$%#x", uint32(x)) + } + return fmt.Sprintf("$%#x", int64(x)) + } + return x.String() +} + +var gccRegName = [...]string{ + 0: "REG0", + AL: "%al", + CL: "%cl", + BL: "%bl", + DL: "%dl", + AH: "%ah", + CH: "%ch", + BH: "%bh", + DH: "%dh", + SPB: "%spl", + BPB: "%bpl", + SIB: "%sil", + DIB: "%dil", + R8B: "%r8b", + R9B: "%r9b", + R10B: "%r10b", + R11B: "%r11b", + R12B: "%r12b", + R13B: "%r13b", + R14B: "%r14b", + R15B: "%r15b", + AX: "%ax", + CX: "%cx", + BX: "%bx", + DX: "%dx", + SP: "%sp", + BP: "%bp", + SI: "%si", + DI: "%di", + R8W: "%r8w", + R9W: "%r9w", + R10W: "%r10w", + R11W: "%r11w", + R12W: "%r12w", + R13W: "%r13w", + R14W: "%r14w", + R15W: "%r15w", + EAX: "%eax", + ECX: "%ecx", + EDX: "%edx", + EBX: "%ebx", + ESP: "%esp", + EBP: "%ebp", + ESI: "%esi", + EDI: "%edi", + R8L: "%r8d", + R9L: "%r9d", + R10L: "%r10d", + R11L: "%r11d", + R12L: "%r12d", + R13L: "%r13d", + R14L: "%r14d", + R15L: "%r15d", + RAX: "%rax", + RCX: "%rcx", + RDX: "%rdx", + RBX: "%rbx", + RSP: "%rsp", + RBP: "%rbp", + RSI: "%rsi", + RDI: "%rdi", + R8: "%r8", + R9: "%r9", + R10: "%r10", + R11: "%r11", + R12: "%r12", + R13: "%r13", + R14: "%r14", + R15: "%r15", + IP: "%ip", + EIP: "%eip", + RIP: "%rip", + F0: "%st", + F1: "%st(1)", + F2: "%st(2)", + F3: "%st(3)", + F4: "%st(4)", + F5: "%st(5)", + F6: "%st(6)", + F7: "%st(7)", + M0: "%mm0", + M1: "%mm1", + M2: "%mm2", + M3: "%mm3", + M4: "%mm4", + M5: "%mm5", + M6: "%mm6", + M7: "%mm7", + X0: "%xmm0", + X1: "%xmm1", + X2: "%xmm2", + X3: "%xmm3", + X4: "%xmm4", + X5: "%xmm5", + X6: "%xmm6", + X7: "%xmm7", + X8: "%xmm8", + X9: "%xmm9", + X10: "%xmm10", + X11: "%xmm11", + X12: "%xmm12", + X13: "%xmm13", + X14: "%xmm14", + X15: "%xmm15", + CS: "%cs", + SS: "%ss", + DS: "%ds", + ES: "%es", + FS: "%fs", + GS: "%gs", + GDTR: "%gdtr", + IDTR: "%idtr", + LDTR: "%ldtr", + MSW: "%msw", + TASK: "%task", + CR0: "%cr0", + CR1: "%cr1", + CR2: "%cr2", + CR3: "%cr3", + CR4: "%cr4", + CR5: "%cr5", + CR6: "%cr6", + CR7: "%cr7", + CR8: "%cr8", + CR9: "%cr9", + CR10: "%cr10", + CR11: "%cr11", + CR12: "%cr12", + CR13: "%cr13", + CR14: "%cr14", + CR15: "%cr15", + DR0: "%db0", + DR1: "%db1", + DR2: "%db2", + DR3: "%db3", + DR4: "%db4", + DR5: "%db5", + DR6: "%db6", + DR7: "%db7", + TR0: "%tr0", + TR1: "%tr1", + TR2: "%tr2", + TR3: "%tr3", + TR4: "%tr4", + TR5: "%tr5", + TR6: "%tr6", + TR7: "%tr7", +} + +var gnuOp = map[Op]string{ + CBW: "cbtw", + CDQ: "cltd", + CMPSD: "cmpsl", + CMPSD_XMM: "cmpsd", + CWD: "cwtd", + CWDE: "cwtl", + CQO: "cqto", + INSD: "insl", + IRET: "iretw", + IRETD: "iret", + IRETQ: "iretq", + LODSB: "lods", + LODSD: "lods", + LODSQ: "lods", + LODSW: "lods", + MOVSD: "movsl", + MOVSD_XMM: "movsd", + OUTSD: "outsl", + POPA: "popaw", + POPAD: "popa", + POPF: "popfw", + POPFD: "popf", + PUSHA: "pushaw", + PUSHAD: "pusha", + PUSHF: "pushfw", + PUSHFD: "pushf", + SCASB: "scas", + SCASD: "scas", + SCASQ: "scas", + SCASW: "scas", + STOSB: "stos", + STOSD: "stos", + STOSQ: "stos", + STOSW: "stos", + XLATB: "xlat", +} + +var cmppsOps = []string{ + "cmpeq", + "cmplt", + "cmple", + "cmpunord", + "cmpneq", + "cmpnlt", + "cmpnle", + "cmpord", +} + +var pclmulqOps = []string{ + "pclmullqlqdq", + "pclmulhqlqdq", + "pclmullqhqdq", + "pclmulhqhqdq", +} + +func countPrefix(inst *Inst, target Prefix) int { + n := 0 + for _, p := range inst.Prefix { + if p&0xFF == target&0xFF { + n++ + } + } + return n +} + +func markLastImplicit(inst *Inst, prefix Prefix) bool { + for i := len(inst.Prefix) - 1; i >= 0; i-- { + p := inst.Prefix[i] + if p&0xFF == prefix { + inst.Prefix[i] |= PrefixImplicit + return true + } + } + return false +} + +func unmarkImplicit(inst *Inst, prefix Prefix) { + for i := len(inst.Prefix) - 1; i >= 0; i-- { + p := inst.Prefix[i] + if p&0xFF == prefix { + inst.Prefix[i] &^= PrefixImplicit + } + } +} + +func byteSizeSuffix(b int) string { + switch b { + case 1: + return "b" + case 2: + return "w" + case 4: + return "l" + case 8: + return "q" + } + return "" +} + +func argBytes(inst *Inst, arg Arg) int { + if isMem(arg) { + return inst.MemBytes + } + return regBytes(arg) +} + +func isFloat(op Op) bool { + switch op { + case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR: + return true + } + return false +} + +func isFloatInt(op Op) bool { + switch op { + case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR: + return true + } + return false +} diff --git a/vendor/rsc.io/x86/x86asm/inst.go b/vendor/rsc.io/x86/x86asm/inst.go new file mode 100644 index 0000000..eccd954 --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/inst.go @@ -0,0 +1,643 @@ +// 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. +package x86asm + +import ( + "bytes" + "fmt" +) + +// An Inst is a single instruction. +type Inst struct { + Prefix Prefixes // Prefixes applied to the instruction. + Op Op // Opcode mnemonic + Opcode uint32 // Encoded opcode bits, left aligned (first byte is Opcode>>24, etc) + Args 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 + PCRel int // length of PC-relative address in instruction encoding + PCRelOff int // index of start of PC-relative address in instruction encoding +} + +// 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 Prefixes [14]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 Prefix uint16 + +const ( + // Metadata about the role of a prefix in an instruction. + PrefixImplicit Prefix = 0x8000 // prefix is implied by instruction text + PrefixIgnored Prefix = 0x4000 // prefix is ignored: either irrelevant or overridden by a later prefix + PrefixInvalid Prefix = 0x2000 // prefix makes entire instruction invalid (bad LOCK) + + // Memory segment overrides. + PrefixES Prefix = 0x26 // ES segment override + PrefixCS Prefix = 0x2E // CS segment override + PrefixSS Prefix = 0x36 // SS segment override + PrefixDS Prefix = 0x3E // DS segment override + PrefixFS Prefix = 0x64 // FS segment override + PrefixGS Prefix = 0x65 // GS segment override + + // Branch prediction. + PrefixPN Prefix = 0x12E // predict not taken (conditional branch only) + PrefixPT Prefix = 0x13E // predict taken (conditional branch only) + + // Size attributes. + PrefixDataSize Prefix = 0x66 // operand size override + PrefixData16 Prefix = 0x166 + PrefixData32 Prefix = 0x266 + PrefixAddrSize Prefix = 0x67 // address size override + PrefixAddr16 Prefix = 0x167 + PrefixAddr32 Prefix = 0x267 + + // One of a kind. + PrefixLOCK Prefix = 0xF0 // lock + PrefixREPN Prefix = 0xF2 // repeat not zero + PrefixXACQUIRE Prefix = 0x1F2 + PrefixBND Prefix = 0x2F2 + PrefixREP Prefix = 0xF3 // repeat + PrefixXRELEASE 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. + PrefixREX Prefix = 0x40 // REX 64-bit extension prefix + PrefixREXW Prefix = 0x08 // extension bit W (64-bit instruction width) + PrefixREXR Prefix = 0x04 // extension bit R (r field in modrm) + PrefixREXX Prefix = 0x02 // extension bit X (index field in sib) + PrefixREXB 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 Prefix) IsREX() bool { + return p&0xF0 == PrefixREX +} + +func (p Prefix) String() string { + p &^= PrefixImplicit | PrefixIgnored | PrefixInvalid + if s := prefixNames[p]; s != "" { + return s + } + + if p.IsREX() { + s := "REX." + if p&PrefixREXW != 0 { + s += "W" + } + if p&PrefixREXR != 0 { + s += "R" + } + if p&PrefixREXX != 0 { + s += "X" + } + if p&PrefixREXB != 0 { + s += "B" + } + return s + } + + return fmt.Sprintf("Prefix(%#x)", int(p)) +} + +// An Op is an x86 opcode. +type Op uint32 + +func (op Op) String() string { + i := int(op) + if i < 0 || i >= len(opNames) || opNames[i] == "" { + return fmt.Sprintf("Op(%d)", i) + } + return 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 Args [4]Arg + +// An Arg is a single instruction argument, +// one of these types: Reg, Mem, Imm, Rel. +type 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 Reg uint8 + +const ( + _ Reg = iota + + // 8-bit + AL + CL + DL + BL + AH + CH + DH + BH + SPB + BPB + SIB + DIB + R8B + R9B + R10B + R11B + R12B + R13B + R14B + R15B + + // 16-bit + AX + CX + DX + BX + SP + BP + SI + DI + R8W + R9W + R10W + R11W + R12W + R13W + R14W + R15W + + // 32-bit + EAX + ECX + EDX + EBX + ESP + EBP + ESI + EDI + R8L + R9L + R10L + R11L + R12L + R13L + R14L + R15L + + // 64-bit + RAX + RCX + RDX + RBX + RSP + RBP + RSI + RDI + R8 + R9 + R10 + R11 + R12 + R13 + R14 + R15 + + // Instruction pointer. + IP // 16-bit + EIP // 32-bit + RIP // 64-bit + + // 387 floating point registers. + F0 + F1 + F2 + F3 + F4 + F5 + F6 + F7 + + // MMX registers. + M0 + M1 + M2 + M3 + M4 + M5 + M6 + M7 + + // XMM registers. + X0 + X1 + X2 + X3 + X4 + X5 + X6 + X7 + X8 + X9 + X10 + X11 + X12 + X13 + X14 + X15 + + // Segment registers. + ES + CS + SS + DS + FS + GS + + // System registers. + GDTR + IDTR + LDTR + MSW + TASK + + // Control registers. + CR0 + CR1 + CR2 + CR3 + CR4 + CR5 + CR6 + CR7 + CR8 + CR9 + CR10 + CR11 + CR12 + CR13 + CR14 + CR15 + + // Debug registers. + DR0 + DR1 + DR2 + DR3 + DR4 + DR5 + DR6 + DR7 + DR8 + DR9 + DR10 + DR11 + DR12 + DR13 + DR14 + DR15 + + // Task registers. + TR0 + TR1 + TR2 + TR3 + TR4 + TR5 + TR6 + TR7 +) + +const regMax = TR7 + +func (Reg) isArg() {} + +func (r Reg) String() string { + i := int(r) + if i < 0 || i >= len(regNames) || regNames[i] == "" { + return fmt.Sprintf("Reg(%d)", i) + } + return regNames[i] +} + +// A Mem is a memory reference. +// The general form is Segment:[Base+Scale*Index+Disp]. +type Mem struct { + Segment Reg + Base Reg + Scale uint8 + Index Reg + Disp int64 +} + +func (Mem) isArg() {} + +func (m 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 Rel int32 + +func (Rel) isArg() {} + +func (r Rel) String() string { + return fmt.Sprintf(".%+d", r) +} + +// An Imm is an integer constant. +type Imm int64 + +func (Imm) isArg() {} + +func (i Imm) String() string { + return fmt.Sprintf("%#x", int64(i)) +} + +func (i Inst) String() string { + var buf bytes.Buffer + for _, p := range i.Prefix { + if p == 0 { + break + } + if p&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 isReg(a Arg) bool { + _, ok := a.(Reg) + return ok +} + +func isSegReg(a Arg) bool { + r, ok := a.(Reg) + return ok && ES <= r && r <= GS +} + +func isMem(a Arg) bool { + _, ok := a.(Mem) + return ok +} + +func isImm(a Arg) bool { + _, ok := a.(Imm) + return ok +} + +func regBytes(a Arg) int { + r, ok := a.(Reg) + if !ok { + return 0 + } + if AL <= r && r <= R15B { + return 1 + } + if AX <= r && r <= R15W { + return 2 + } + if EAX <= r && r <= R15L { + return 4 + } + if RAX <= r && r <= R15 { + return 8 + } + return 0 +} + +func isSegment(p Prefix) bool { + switch p { + case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS: + return true + } + return false +} + +// The Op definitions and string list are in tables.go. + +var prefixNames = map[Prefix]string{ + PrefixCS: "CS", + PrefixDS: "DS", + PrefixES: "ES", + PrefixFS: "FS", + PrefixGS: "GS", + PrefixSS: "SS", + PrefixLOCK: "LOCK", + PrefixREP: "REP", + PrefixREPN: "REPN", + PrefixAddrSize: "ADDRSIZE", + PrefixDataSize: "DATASIZE", + PrefixAddr16: "ADDR16", + PrefixData16: "DATA16", + PrefixAddr32: "ADDR32", + PrefixData32: "DATA32", + PrefixBND: "BND", + PrefixXACQUIRE: "XACQUIRE", + PrefixXRELEASE: "XRELEASE", + PrefixREX: "REX", + PrefixPT: "PT", + PrefixPN: "PN", +} + +var regNames = [...]string{ + AL: "AL", + CL: "CL", + BL: "BL", + DL: "DL", + AH: "AH", + CH: "CH", + BH: "BH", + DH: "DH", + SPB: "SPB", + BPB: "BPB", + SIB: "SIB", + DIB: "DIB", + R8B: "R8B", + R9B: "R9B", + R10B: "R10B", + R11B: "R11B", + R12B: "R12B", + R13B: "R13B", + R14B: "R14B", + R15B: "R15B", + AX: "AX", + CX: "CX", + BX: "BX", + DX: "DX", + SP: "SP", + BP: "BP", + SI: "SI", + DI: "DI", + R8W: "R8W", + R9W: "R9W", + R10W: "R10W", + R11W: "R11W", + R12W: "R12W", + R13W: "R13W", + R14W: "R14W", + R15W: "R15W", + EAX: "EAX", + ECX: "ECX", + EDX: "EDX", + EBX: "EBX", + ESP: "ESP", + EBP: "EBP", + ESI: "ESI", + EDI: "EDI", + R8L: "R8L", + R9L: "R9L", + R10L: "R10L", + R11L: "R11L", + R12L: "R12L", + R13L: "R13L", + R14L: "R14L", + R15L: "R15L", + RAX: "RAX", + RCX: "RCX", + RDX: "RDX", + RBX: "RBX", + RSP: "RSP", + RBP: "RBP", + RSI: "RSI", + RDI: "RDI", + R8: "R8", + R9: "R9", + R10: "R10", + R11: "R11", + R12: "R12", + R13: "R13", + R14: "R14", + R15: "R15", + IP: "IP", + EIP: "EIP", + RIP: "RIP", + F0: "F0", + F1: "F1", + F2: "F2", + F3: "F3", + F4: "F4", + F5: "F5", + F6: "F6", + F7: "F7", + M0: "M0", + M1: "M1", + M2: "M2", + M3: "M3", + M4: "M4", + M5: "M5", + M6: "M6", + M7: "M7", + X0: "X0", + X1: "X1", + X2: "X2", + X3: "X3", + X4: "X4", + X5: "X5", + X6: "X6", + X7: "X7", + X8: "X8", + X9: "X9", + X10: "X10", + X11: "X11", + X12: "X12", + X13: "X13", + X14: "X14", + X15: "X15", + CS: "CS", + SS: "SS", + DS: "DS", + ES: "ES", + FS: "FS", + GS: "GS", + GDTR: "GDTR", + IDTR: "IDTR", + LDTR: "LDTR", + MSW: "MSW", + TASK: "TASK", + CR0: "CR0", + CR1: "CR1", + CR2: "CR2", + CR3: "CR3", + CR4: "CR4", + CR5: "CR5", + CR6: "CR6", + CR7: "CR7", + CR8: "CR8", + CR9: "CR9", + CR10: "CR10", + CR11: "CR11", + CR12: "CR12", + CR13: "CR13", + CR14: "CR14", + CR15: "CR15", + DR0: "DR0", + DR1: "DR1", + DR2: "DR2", + DR3: "DR3", + DR4: "DR4", + DR5: "DR5", + DR6: "DR6", + DR7: "DR7", + DR8: "DR8", + DR9: "DR9", + DR10: "DR10", + DR11: "DR11", + DR12: "DR12", + DR13: "DR13", + DR14: "DR14", + DR15: "DR15", + TR0: "TR0", + TR1: "TR1", + TR2: "TR2", + TR3: "TR3", + TR4: "TR4", + TR5: "TR5", + TR6: "TR6", + TR7: "TR7", +} diff --git a/vendor/rsc.io/x86/x86asm/intel.go b/vendor/rsc.io/x86/x86asm/intel.go new file mode 100644 index 0000000..90af9dd --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/intel.go @@ -0,0 +1,518 @@ +// 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 + +import ( + "fmt" + "strings" +) + +// IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool. +func IntelSyntax(inst Inst) string { + var iargs []Arg + for _, a := range inst.Args { + if a == nil { + break + } + iargs = append(iargs, a) + } + + switch inst.Op { + case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, LOOPNE, JCXZ, JECXZ, JRCXZ, LOOP, LOOPE, MOV, XLATB: + if inst.Op == MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 { + break + } + for i, p := range inst.Prefix { + if p&0xFF == PrefixAddrSize { + inst.Prefix[i] &^= PrefixImplicit + } + } + } + + switch inst.Op { + case MOV: + dst, _ := inst.Args[0].(Reg) + src, _ := inst.Args[1].(Reg) + if ES <= dst && dst <= GS && EAX <= src && src <= R15L { + src -= EAX - AX + iargs[1] = src + } + if ES <= dst && dst <= GS && RAX <= src && src <= R15 { + src -= RAX - AX + iargs[1] = src + } + + if inst.Opcode>>24&^3 == 0xA0 { + for i, p := range inst.Prefix { + if p&0xFF == PrefixAddrSize { + inst.Prefix[i] |= PrefixImplicit + } + } + } + } + + switch inst.Op { + case AAM, AAD: + if imm, ok := iargs[0].(Imm); ok { + if inst.DataSize == 32 { + iargs[0] = Imm(uint32(int8(imm))) + } else if inst.DataSize == 16 { + iargs[0] = Imm(uint16(int8(imm))) + } + } + + case PUSH: + if imm, ok := iargs[0].(Imm); ok { + iargs[0] = Imm(uint32(imm)) + } + } + + for _, p := range inst.Prefix { + if p&PrefixImplicit != 0 { + for j, pj := range inst.Prefix { + if pj&0xFF == p&0xFF { + inst.Prefix[j] |= PrefixImplicit + } + } + } + } + + if inst.Op != 0 { + for i, p := range inst.Prefix { + switch p &^ PrefixIgnored { + case PrefixData16, PrefixData32, PrefixCS, PrefixDS, PrefixES, PrefixSS: + inst.Prefix[i] |= PrefixImplicit + } + if p.IsREX() { + inst.Prefix[i] |= PrefixImplicit + } + } + } + + if isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ { + for i, p := range inst.Prefix { + if p == PrefixPT || p == PrefixPN { + inst.Prefix[i] |= PrefixImplicit + } + } + } + + switch inst.Op { + case AAA, AAS, CBW, CDQE, CLC, CLD, CLI, CLTS, CMC, CPUID, CQO, CWD, DAA, DAS, + FDECSTP, FINCSTP, FNCLEX, FNINIT, FNOP, FWAIT, HLT, + ICEBP, INSB, INSD, INSW, INT, INTO, INVD, IRET, IRETQ, + LAHF, LEAVE, LRET, MONITOR, MWAIT, NOP, OUTSB, OUTSD, OUTSW, + PAUSE, POPA, POPF, POPFQ, PUSHA, PUSHF, PUSHFQ, + RDMSR, RDPMC, RDTSC, RDTSCP, RET, RSM, + SAHF, STC, STD, STI, SYSENTER, SYSEXIT, SYSRET, + UD2, WBINVD, WRMSR, XEND, XLATB, XTEST: + + if inst.Op == NOP && inst.Opcode>>24 != 0x90 { + break + } + if inst.Op == RET && inst.Opcode>>24 != 0xC3 { + break + } + if inst.Op == INT && inst.Opcode>>24 != 0xCC { + break + } + if inst.Op == LRET && inst.Opcode>>24 != 0xcb { + break + } + for i, p := range inst.Prefix { + if p&0xFF == PrefixDataSize { + inst.Prefix[i] &^= PrefixImplicit | PrefixIgnored + } + } + + case 0: + // ok + } + + switch inst.Op { + case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, MONITOR, MWAIT, XLATB: + iargs = nil + + case STOSB, STOSW, STOSD, STOSQ: + iargs = iargs[:1] + + case LODSB, LODSW, LODSD, LODSQ, SCASB, SCASW, SCASD, 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&(PrefixImplicit|PrefixIgnored) != 0 { + continue + } + switch p { + default: + prefix += strings.ToLower(p.String()) + " " + case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS: + if inst.Op == 0 { + prefix += strings.ToLower(p.String()) + " " + } + case PrefixREPN: + prefix += "repne " + case PrefixLOCK: + prefixBits |= haveLock + case PrefixData16, PrefixDataSize: + prefixBits |= haveData16 + case PrefixData32: + prefixBits |= haveData32 + case PrefixAddrSize, PrefixAddr16: + prefixBits |= haveAddr16 + case PrefixAddr32: + prefixBits |= haveAddr32 + case PrefixXACQUIRE: + prefixBits |= haveXacquire + case PrefixXRELEASE: + prefixBits |= haveXrelease + case PrefixPT: + prefixBits |= haveHintTaken + case PrefixPN: + prefixBits |= haveHintNotTaken + case PrefixBND: + prefixBits |= haveBnd + } + } + switch inst.Op { + case JMP: + if inst.Opcode>>24 == 0xEB { + prefixBits &^= haveBnd + } + case RET, 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 "" + } + return prefix[:len(prefix)-1] + } + + var args []string + for _, a := range iargs { + if a == nil { + break + } + args = append(args, intelArg(&inst, a)) + } + + var op string + switch inst.Op { + case NOP: + if inst.Opcode>>24 == 0x0F { + if inst.DataSize == 16 { + args = append(args, "ax") + } else { + args = append(args, "eax") + } + } + + case BLENDVPD, BLENDVPS, PBLENDVB: + args = args[:2] + + case INT: + if inst.Opcode>>24 == 0xCC { + args = nil + op = "int3" + } + + case LCALL, LJMP: + if len(args) == 2 { + args[0], args[1] = args[1], args[0] + } + + case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN: + if len(args) == 0 { + args = append(args, "st0") + } + + case FPTAN, FSINCOS, FUCOMPP, FCOMPP, FYL2X, FPATAN, FXTRACT, FPREM1, FPREM, FYL2XP1, FSCALE: + if len(args) == 0 { + args = []string{"st0", "st1"} + } + + case FST, FSTP, FISTTP, FIST, FISTP, FBSTP: + if len(args) == 1 { + args = append(args, "st0") + } + + case FLD, FXCH, FCOM, FCOMP, FIADD, FIMUL, FICOM, FICOMP, FISUBR, FIDIV, FUCOM, FUCOMP, FILD, FBLD, FADD, FMUL, FSUB, FSUBR, FISUB, FDIV, FDIVR, FIDIVR: + if len(args) == 1 { + args = []string{"st0", args[0]} + } + + case MASKMOVDQU, MASKMOVQ, XLATB, OUTSB, OUTSW, OUTSD: + FixSegment: + for i := len(inst.Prefix) - 1; i >= 0; i-- { + p := inst.Prefix[i] & 0xFF + switch p { + case PrefixCS, PrefixES, PrefixFS, PrefixGS, PrefixSS: + if inst.Mode != 64 || p == PrefixFS || p == PrefixGS { + args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String())) + break FixSegment + } + case PrefixDS: + if inst.Mode != 64 { + break FixSegment + } + } + } + } + + if op == "" { + op = intelOp[inst.Op] + } + if op == "" { + op = strings.ToLower(inst.Op.String()) + } + if args != nil { + op += " " + strings.Join(args, ", ") + } + return prefix + op +} + +func intelArg(inst *Inst, arg Arg) string { + switch a := arg.(type) { + case Imm: + if inst.Mode == 32 { + return fmt.Sprintf("%#x", uint32(a)) + } + if Imm(int32(a)) == a { + return fmt.Sprintf("%#x", int64(a)) + } + return fmt.Sprintf("%#x", uint64(a)) + case Mem: + if a.Base == EIP { + a.Base = 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 INVLPG: + prefix = "byte " + case STOSB, MOVSB, CMPSB, LODSB, SCASB: + prefix = "byte " + case STOSW, MOVSW, CMPSW, LODSW, SCASW: + prefix = "word " + case STOSD, MOVSD, CMPSD, LODSD, SCASD: + prefix = "dword " + case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ: + prefix = "qword " + case LAR: + prefix = "word " + case BOUND: + if inst.Mode == 32 { + prefix = "qword " + } else { + prefix = "dword " + } + case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH: + prefix = "zmmword " + } + switch inst.Op { + case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ: + switch a.Base { + case DI, EDI, RDI: + if a.Segment == ES { + a.Segment = 0 + } + case SI, ESI, RSI: + if a.Segment == DS { + a.Segment = 0 + } + } + case LEA: + a.Segment = 0 + default: + switch a.Base { + case SP, ESP, RSP, BP, EBP, RBP: + if a.Segment == SS { + a.Segment = 0 + } + default: + if a.Segment == DS { + a.Segment = 0 + } + } + } + + if inst.Mode == 64 && a.Segment != FS && a.Segment != GS { + a.Segment = 0 + } + + prefix += "ptr " + if a.Segment != 0 { + prefix += strings.ToLower(a.Segment.String()) + ":" + } + prefix += "[" + if a.Base != 0 { + prefix += intelArg(inst, a.Base) + } + if a.Scale != 0 && a.Index != 0 { + if a.Base != 0 { + prefix += "+" + } + prefix += fmt.Sprintf("%s*%d", 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 Rel: + return fmt.Sprintf(".%+#x", int64(a)) + case Reg: + if int(a) < len(intelReg) && intelReg[a] != "" { + return intelReg[a] + } + } + return strings.ToLower(arg.String()) +} + +var intelOp = map[Op]string{ + JAE: "jnb", + JA: "jnbe", + JGE: "jnl", + JNE: "jnz", + JG: "jnle", + JE: "jz", + SETAE: "setnb", + SETA: "setnbe", + SETGE: "setnl", + SETNE: "setnz", + SETG: "setnle", + SETE: "setz", + CMOVAE: "cmovnb", + CMOVA: "cmovnbe", + CMOVGE: "cmovnl", + CMOVNE: "cmovnz", + CMOVG: "cmovnle", + CMOVE: "cmovz", + LCALL: "call far", + LJMP: "jmp far", + LRET: "ret far", + ICEBP: "int1", + MOVSD_XMM: "movsd", + XLATB: "xlat", +} + +var intelReg = [...]string{ + F0: "st0", + F1: "st1", + F2: "st2", + F3: "st3", + F4: "st4", + F5: "st5", + F6: "st6", + F7: "st7", + M0: "mmx0", + M1: "mmx1", + M2: "mmx2", + M3: "mmx3", + M4: "mmx4", + M5: "mmx5", + M6: "mmx6", + M7: "mmx7", + X0: "xmm0", + X1: "xmm1", + X2: "xmm2", + X3: "xmm3", + X4: "xmm4", + X5: "xmm5", + X6: "xmm6", + X7: "xmm7", + X8: "xmm8", + X9: "xmm9", + X10: "xmm10", + X11: "xmm11", + X12: "xmm12", + X13: "xmm13", + X14: "xmm14", + X15: "xmm15", + + // TODO: Maybe the constants are named wrong. + SPB: "spl", + BPB: "bpl", + SIB: "sil", + DIB: "dil", + + R8L: "r8d", + R9L: "r9d", + R10L: "r10d", + R11L: "r11d", + R12L: "r12d", + R13L: "r13d", + R14L: "r14d", + R15L: "r15d", +} diff --git a/vendor/rsc.io/x86/x86asm/plan9x.go b/vendor/rsc.io/x86/x86asm/plan9x.go new file mode 100644 index 0000000..ccbdea4 --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/plan9x.go @@ -0,0 +1,346 @@ +// 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 + +import ( + "fmt" + "strings" +) + +// 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 plan9Syntax(inst 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, plan9Arg(&inst, pc, symname, a)) + } + + var last Prefix + for _, p := range inst.Prefix { + if p == 0 || p.IsREX() { + break + } + last = p + } + + prefix := "" + switch last & 0xFF { + case 0, 0x66, 0x67: + // ignore + case PrefixREPN: + prefix += "REPNE " + default: + prefix += last.String() + " " + } + + op := inst.Op.String() + if 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 plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { + switch a := arg.(type) { + case Reg: + return plan9Reg[a] + case 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 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 Imm(int32(a)) == a { + return fmt.Sprintf("$%#x", int64(a)) + } + return fmt.Sprintf("$%#x", uint64(a)) + case 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:", plan9Reg[a.Segment]) + } + if a.Disp != 0 { + s += fmt.Sprintf("%#x", a.Disp) + } else { + s += "0" + } + if a.Base != 0 { + s += fmt.Sprintf("(%s)", plan9Reg[a.Base]) + } + if a.Index != 0 && a.Scale != 0 { + s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale) + } + return s + } + return arg.String() +} + +var plan9Suffix = [maxOp + 1]bool{ + ADC: true, + ADD: true, + AND: true, + BSF: true, + BSR: true, + BT: true, + BTC: true, + BTR: true, + BTS: true, + CMP: true, + CMPXCHG: true, + CVTSI2SD: true, + CVTSI2SS: true, + CVTSD2SI: true, + CVTSS2SI: true, + CVTTSD2SI: true, + CVTTSS2SI: true, + DEC: true, + DIV: true, + FLDENV: true, + FRSTOR: true, + IDIV: true, + IMUL: true, + IN: true, + INC: true, + LEA: true, + MOV: true, + MOVNTI: true, + MUL: true, + NEG: true, + NOP: true, + NOT: true, + OR: true, + OUT: true, + POP: true, + POPA: true, + PUSH: true, + PUSHA: true, + RCL: true, + RCR: true, + ROL: true, + ROR: true, + SAR: true, + SBB: true, + SHL: true, + SHLD: true, + SHR: true, + SHRD: true, + SUB: true, + TEST: true, + XADD: true, + XCHG: true, + XOR: true, +} + +var plan9Reg = [...]string{ + AL: "AL", + CL: "CL", + BL: "BL", + DL: "DL", + AH: "AH", + CH: "CH", + BH: "BH", + DH: "DH", + SPB: "SP", + BPB: "BP", + SIB: "SI", + DIB: "DI", + R8B: "R8", + R9B: "R9", + R10B: "R10", + R11B: "R11", + R12B: "R12", + R13B: "R13", + R14B: "R14", + R15B: "R15", + AX: "AX", + CX: "CX", + BX: "BX", + DX: "DX", + SP: "SP", + BP: "BP", + SI: "SI", + DI: "DI", + R8W: "R8", + R9W: "R9", + R10W: "R10", + R11W: "R11", + R12W: "R12", + R13W: "R13", + R14W: "R14", + R15W: "R15", + EAX: "AX", + ECX: "CX", + EDX: "DX", + EBX: "BX", + ESP: "SP", + EBP: "BP", + ESI: "SI", + EDI: "DI", + R8L: "R8", + R9L: "R9", + R10L: "R10", + R11L: "R11", + R12L: "R12", + R13L: "R13", + R14L: "R14", + R15L: "R15", + RAX: "AX", + RCX: "CX", + RDX: "DX", + RBX: "BX", + RSP: "SP", + RBP: "BP", + RSI: "SI", + RDI: "DI", + R8: "R8", + R9: "R9", + R10: "R10", + R11: "R11", + R12: "R12", + R13: "R13", + R14: "R14", + R15: "R15", + IP: "IP", + EIP: "IP", + RIP: "IP", + F0: "F0", + F1: "F1", + F2: "F2", + F3: "F3", + F4: "F4", + F5: "F5", + F6: "F6", + F7: "F7", + M0: "M0", + M1: "M1", + M2: "M2", + M3: "M3", + M4: "M4", + M5: "M5", + M6: "M6", + M7: "M7", + X0: "X0", + X1: "X1", + X2: "X2", + X3: "X3", + X4: "X4", + X5: "X5", + X6: "X6", + X7: "X7", + X8: "X8", + X9: "X9", + X10: "X10", + X11: "X11", + X12: "X12", + X13: "X13", + X14: "X14", + X15: "X15", + CS: "CS", + SS: "SS", + DS: "DS", + ES: "ES", + FS: "FS", + GS: "GS", + GDTR: "GDTR", + IDTR: "IDTR", + LDTR: "LDTR", + MSW: "MSW", + TASK: "TASK", + CR0: "CR0", + CR1: "CR1", + CR2: "CR2", + CR3: "CR3", + CR4: "CR4", + CR5: "CR5", + CR6: "CR6", + CR7: "CR7", + CR8: "CR8", + CR9: "CR9", + CR10: "CR10", + CR11: "CR11", + CR12: "CR12", + CR13: "CR13", + CR14: "CR14", + CR15: "CR15", + DR0: "DR0", + DR1: "DR1", + DR2: "DR2", + DR3: "DR3", + DR4: "DR4", + DR5: "DR5", + DR6: "DR6", + DR7: "DR7", + DR8: "DR8", + DR9: "DR9", + DR10: "DR10", + DR11: "DR11", + DR12: "DR12", + DR13: "DR13", + DR14: "DR14", + DR15: "DR15", + TR0: "TR0", + TR1: "TR1", + TR2: "TR2", + TR3: "TR3", + TR4: "TR4", + TR5: "TR5", + TR6: "TR6", + TR7: "TR7", +} diff --git a/vendor/rsc.io/x86/x86asm/tables.go b/vendor/rsc.io/x86/x86asm/tables.go new file mode 100644 index 0000000..3d08d5e --- /dev/null +++ b/vendor/rsc.io/x86/x86asm/tables.go @@ -0,0 +1,9760 @@ +// DO NOT EDIT +// generated by: x86map -fmt=decoder ../x86.csv + +package x86asm + +var decoder = [...]uint16{ + uint16(xFail), + /*1*/ uint16(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(xFail), + /*490*/ uint16(xSetOp), uint16(ADD), + /*492*/ uint16(xReadSlashR), + /*493*/ uint16(xArgRM8), + /*494*/ uint16(xArgR8), + /*495*/ uint16(xMatch), + /*496*/ uint16(xCondIs64), 499, 515, + /*499*/ uint16(xCondDataSize), 503, 509, 0, + /*503*/ uint16(xSetOp), uint16(ADD), + /*505*/ uint16(xReadSlashR), + /*506*/ uint16(xArgRM16), + /*507*/ uint16(xArgR16), + /*508*/ uint16(xMatch), + /*509*/ uint16(xSetOp), uint16(ADD), + /*511*/ uint16(xReadSlashR), + /*512*/ uint16(xArgRM32), + /*513*/ uint16(xArgR32), + /*514*/ uint16(xMatch), + /*515*/ uint16(xCondDataSize), 503, 509, 519, + /*519*/ uint16(xSetOp), uint16(ADD), + /*521*/ uint16(xReadSlashR), + /*522*/ uint16(xArgRM64), + /*523*/ uint16(xArgR64), + /*524*/ uint16(xMatch), + /*525*/ uint16(xSetOp), uint16(ADD), + /*527*/ uint16(xReadSlashR), + /*528*/ uint16(xArgR8), + /*529*/ uint16(xArgRM8), + /*530*/ uint16(xMatch), + /*531*/ uint16(xCondIs64), 534, 550, + /*534*/ uint16(xCondDataSize), 538, 544, 0, + /*538*/ uint16(xSetOp), uint16(ADD), + /*540*/ uint16(xReadSlashR), + /*541*/ uint16(xArgR16), + /*542*/ uint16(xArgRM16), + /*543*/ uint16(xMatch), + /*544*/ uint16(xSetOp), uint16(ADD), + /*546*/ uint16(xReadSlashR), + /*547*/ uint16(xArgR32), + /*548*/ uint16(xArgRM32), + /*549*/ uint16(xMatch), + /*550*/ uint16(xCondDataSize), 538, 544, 554, + /*554*/ uint16(xSetOp), uint16(ADD), + /*556*/ uint16(xReadSlashR), + /*557*/ uint16(xArgR64), + /*558*/ uint16(xArgRM64), + /*559*/ uint16(xMatch), + /*560*/ uint16(xSetOp), uint16(ADD), + /*562*/ uint16(xReadIb), + /*563*/ uint16(xArgAL), + /*564*/ uint16(xArgImm8u), + /*565*/ uint16(xMatch), + /*566*/ uint16(xCondIs64), 569, 585, + /*569*/ uint16(xCondDataSize), 573, 579, 0, + /*573*/ uint16(xSetOp), uint16(ADD), + /*575*/ uint16(xReadIw), + /*576*/ uint16(xArgAX), + /*577*/ uint16(xArgImm16), + /*578*/ uint16(xMatch), + /*579*/ uint16(xSetOp), uint16(ADD), + /*581*/ uint16(xReadId), + /*582*/ uint16(xArgEAX), + /*583*/ uint16(xArgImm32), + /*584*/ uint16(xMatch), + /*585*/ uint16(xCondDataSize), 573, 579, 589, + /*589*/ uint16(xSetOp), uint16(ADD), + /*591*/ uint16(xReadId), + /*592*/ uint16(xArgRAX), + /*593*/ uint16(xArgImm32), + /*594*/ uint16(xMatch), + /*595*/ uint16(xCondIs64), 598, 0, + /*598*/ uint16(xSetOp), uint16(PUSH), + /*600*/ uint16(xArgES), + /*601*/ uint16(xMatch), + /*602*/ uint16(xCondIs64), 605, 0, + /*605*/ uint16(xSetOp), uint16(POP), + /*607*/ uint16(xArgES), + /*608*/ uint16(xMatch), + /*609*/ uint16(xSetOp), uint16(OR), + /*611*/ uint16(xReadSlashR), + /*612*/ uint16(xArgRM8), + /*613*/ uint16(xArgR8), + /*614*/ uint16(xMatch), + /*615*/ uint16(xCondIs64), 618, 634, + /*618*/ uint16(xCondDataSize), 622, 628, 0, + /*622*/ uint16(xSetOp), uint16(OR), + /*624*/ uint16(xReadSlashR), + /*625*/ uint16(xArgRM16), + /*626*/ uint16(xArgR16), + /*627*/ uint16(xMatch), + /*628*/ uint16(xSetOp), uint16(OR), + /*630*/ uint16(xReadSlashR), + /*631*/ uint16(xArgRM32), + /*632*/ uint16(xArgR32), + /*633*/ uint16(xMatch), + /*634*/ uint16(xCondDataSize), 622, 628, 638, + /*638*/ uint16(xSetOp), uint16(OR), + /*640*/ uint16(xReadSlashR), + /*641*/ uint16(xArgRM64), + /*642*/ uint16(xArgR64), + /*643*/ uint16(xMatch), + /*644*/ uint16(xSetOp), uint16(OR), + /*646*/ uint16(xReadSlashR), + /*647*/ uint16(xArgR8), + /*648*/ uint16(xArgRM8), + /*649*/ uint16(xMatch), + /*650*/ uint16(xCondIs64), 653, 669, + /*653*/ uint16(xCondDataSize), 657, 663, 0, + /*657*/ uint16(xSetOp), uint16(OR), + /*659*/ uint16(xReadSlashR), + /*660*/ uint16(xArgR16), + /*661*/ uint16(xArgRM16), + /*662*/ uint16(xMatch), + /*663*/ uint16(xSetOp), uint16(OR), + /*665*/ uint16(xReadSlashR), + /*666*/ uint16(xArgR32), + /*667*/ uint16(xArgRM32), + /*668*/ uint16(xMatch), + /*669*/ uint16(xCondDataSize), 657, 663, 673, + /*673*/ uint16(xSetOp), uint16(OR), + /*675*/ uint16(xReadSlashR), + /*676*/ uint16(xArgR64), + /*677*/ uint16(xArgRM64), + /*678*/ uint16(xMatch), + /*679*/ uint16(xSetOp), uint16(OR), + /*681*/ uint16(xReadIb), + /*682*/ uint16(xArgAL), + /*683*/ uint16(xArgImm8u), + /*684*/ uint16(xMatch), + /*685*/ uint16(xCondIs64), 688, 704, + /*688*/ uint16(xCondDataSize), 692, 698, 0, + /*692*/ uint16(xSetOp), uint16(OR), + /*694*/ uint16(xReadIw), + /*695*/ uint16(xArgAX), + /*696*/ uint16(xArgImm16), + /*697*/ uint16(xMatch), + /*698*/ uint16(xSetOp), uint16(OR), + /*700*/ uint16(xReadId), + /*701*/ uint16(xArgEAX), + /*702*/ uint16(xArgImm32), + /*703*/ uint16(xMatch), + /*704*/ uint16(xCondDataSize), 692, 698, 708, + /*708*/ uint16(xSetOp), uint16(OR), + /*710*/ uint16(xReadId), + /*711*/ uint16(xArgRAX), + /*712*/ uint16(xArgImm32), + /*713*/ uint16(xMatch), + /*714*/ uint16(xCondIs64), 717, 0, + /*717*/ uint16(xSetOp), uint16(PUSH), + /*719*/ uint16(xArgCS), + /*720*/ uint16(xMatch), + /*721*/ uint16(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(xFail), + /*1180*/ uint16(xCondSlashR), + 1189, // 0 + 1205, // 1 + 1221, // 2 + 1225, // 3 + 1229, // 4 + 1233, // 5 + 0, // 6 + 0, // 7 + /*1189*/ uint16(xCondDataSize), 1193, 1197, 1201, + /*1193*/ uint16(xSetOp), uint16(SLDT), + /*1195*/ uint16(xArgRM16), + /*1196*/ uint16(xMatch), + /*1197*/ uint16(xSetOp), uint16(SLDT), + /*1199*/ uint16(xArgR32M16), + /*1200*/ uint16(xMatch), + /*1201*/ uint16(xSetOp), uint16(SLDT), + /*1203*/ uint16(xArgR64M16), + /*1204*/ uint16(xMatch), + /*1205*/ uint16(xCondDataSize), 1209, 1213, 1217, + /*1209*/ uint16(xSetOp), uint16(STR), + /*1211*/ uint16(xArgRM16), + /*1212*/ uint16(xMatch), + /*1213*/ uint16(xSetOp), uint16(STR), + /*1215*/ uint16(xArgR32M16), + /*1216*/ uint16(xMatch), + /*1217*/ uint16(xSetOp), uint16(STR), + /*1219*/ uint16(xArgR64M16), + /*1220*/ uint16(xMatch), + /*1221*/ uint16(xSetOp), uint16(LLDT), + /*1223*/ uint16(xArgRM16), + /*1224*/ uint16(xMatch), + /*1225*/ uint16(xSetOp), uint16(LTR), + /*1227*/ uint16(xArgRM16), + /*1228*/ uint16(xMatch), + /*1229*/ uint16(xSetOp), uint16(VERR), + /*1231*/ uint16(xArgRM16), + /*1232*/ uint16(xMatch), + /*1233*/ uint16(xSetOp), uint16(VERW), + /*1235*/ uint16(xArgRM16), + /*1236*/ uint16(xMatch), + /*1237*/ uint16(xCondByte), 8, + 0xC8, 1318, + 0xC9, 1321, + 0xD0, 1324, + 0xD1, 1327, + 0xD5, 1330, + 0xD6, 1333, + 0xF8, 1336, + 0xF9, 1342, + /*1255*/ uint16(xCondSlashR), + 1264, // 0 + 1268, // 1 + 1272, // 2 + 1283, // 3 + 1294, // 4 + 0, // 5 + 1310, // 6 + 1314, // 7 + /*1264*/ uint16(xSetOp), uint16(SGDT), + /*1266*/ uint16(xArgM), + /*1267*/ uint16(xMatch), + /*1268*/ uint16(xSetOp), uint16(SIDT), + /*1270*/ uint16(xArgM), + /*1271*/ uint16(xMatch), + /*1272*/ uint16(xCondIs64), 1275, 1279, + /*1275*/ uint16(xSetOp), uint16(LGDT), + /*1277*/ uint16(xArgM16and32), + /*1278*/ uint16(xMatch), + /*1279*/ uint16(xSetOp), uint16(LGDT), + /*1281*/ uint16(xArgM16and64), + /*1282*/ uint16(xMatch), + /*1283*/ uint16(xCondIs64), 1286, 1290, + /*1286*/ uint16(xSetOp), uint16(LIDT), + /*1288*/ uint16(xArgM16and32), + /*1289*/ uint16(xMatch), + /*1290*/ uint16(xSetOp), uint16(LIDT), + /*1292*/ uint16(xArgM16and64), + /*1293*/ uint16(xMatch), + /*1294*/ uint16(xCondDataSize), 1298, 1302, 1306, + /*1298*/ uint16(xSetOp), uint16(SMSW), + /*1300*/ uint16(xArgRM16), + /*1301*/ uint16(xMatch), + /*1302*/ uint16(xSetOp), uint16(SMSW), + /*1304*/ uint16(xArgR32M16), + /*1305*/ uint16(xMatch), + /*1306*/ uint16(xSetOp), uint16(SMSW), + /*1308*/ uint16(xArgR64M16), + /*1309*/ uint16(xMatch), + /*1310*/ uint16(xSetOp), uint16(LMSW), + /*1312*/ uint16(xArgRM16), + /*1313*/ uint16(xMatch), + /*1314*/ uint16(xSetOp), uint16(INVLPG), + /*1316*/ uint16(xArgM), + /*1317*/ uint16(xMatch), + /*1318*/ uint16(xSetOp), uint16(MONITOR), + /*1320*/ uint16(xMatch), + /*1321*/ uint16(xSetOp), uint16(MWAIT), + /*1323*/ uint16(xMatch), + /*1324*/ uint16(xSetOp), uint16(XGETBV), + /*1326*/ uint16(xMatch), + /*1327*/ uint16(xSetOp), uint16(XSETBV), + /*1329*/ uint16(xMatch), + /*1330*/ uint16(xSetOp), uint16(XEND), + /*1332*/ uint16(xMatch), + /*1333*/ uint16(xSetOp), uint16(XTEST), + /*1335*/ uint16(xMatch), + /*1336*/ uint16(xCondIs64), 0, 1339, + /*1339*/ uint16(xSetOp), uint16(SWAPGS), + /*1341*/ uint16(xMatch), + /*1342*/ uint16(xSetOp), uint16(RDTSCP), + /*1344*/ uint16(xMatch), + /*1345*/ uint16(xCondDataSize), 1349, 1355, 1361, + /*1349*/ uint16(xSetOp), uint16(LAR), + /*1351*/ uint16(xReadSlashR), + /*1352*/ uint16(xArgR16), + /*1353*/ uint16(xArgRM16), + /*1354*/ uint16(xMatch), + /*1355*/ uint16(xSetOp), uint16(LAR), + /*1357*/ uint16(xReadSlashR), + /*1358*/ uint16(xArgR32), + /*1359*/ uint16(xArgR32M16), + /*1360*/ uint16(xMatch), + /*1361*/ uint16(xSetOp), uint16(LAR), + /*1363*/ uint16(xReadSlashR), + /*1364*/ uint16(xArgR64), + /*1365*/ uint16(xArgR64M16), + /*1366*/ uint16(xMatch), + /*1367*/ uint16(xCondDataSize), 1371, 1377, 1383, + /*1371*/ uint16(xSetOp), uint16(LSL), + /*1373*/ uint16(xReadSlashR), + /*1374*/ uint16(xArgR16), + /*1375*/ uint16(xArgRM16), + /*1376*/ uint16(xMatch), + /*1377*/ uint16(xSetOp), uint16(LSL), + /*1379*/ uint16(xReadSlashR), + /*1380*/ uint16(xArgR32), + /*1381*/ uint16(xArgR32M16), + /*1382*/ uint16(xMatch), + /*1383*/ uint16(xSetOp), uint16(LSL), + /*1385*/ uint16(xReadSlashR), + /*1386*/ uint16(xArgR64), + /*1387*/ uint16(xArgR32M16), + /*1388*/ uint16(xMatch), + /*1389*/ uint16(xCondIs64), 0, 1392, + /*1392*/ uint16(xSetOp), uint16(SYSCALL), + /*1394*/ uint16(xMatch), + /*1395*/ uint16(xSetOp), uint16(CLTS), + /*1397*/ uint16(xMatch), + /*1398*/ uint16(xCondIs64), 0, 1401, + /*1401*/ uint16(xSetOp), uint16(SYSRET), + /*1403*/ uint16(xMatch), + /*1404*/ uint16(xSetOp), uint16(INVD), + /*1406*/ uint16(xMatch), + /*1407*/ uint16(xSetOp), uint16(WBINVD), + /*1409*/ uint16(xMatch), + /*1410*/ uint16(xSetOp), uint16(UD2), + /*1412*/ uint16(xMatch), + /*1413*/ uint16(xCondSlashR), + 0, // 0 + 1422, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*1422*/ uint16(xSetOp), uint16(PREFETCHW), + /*1424*/ uint16(xArgM8), + /*1425*/ uint16(xMatch), + /*1426*/ uint16(xCondPrefix), 4, + 0xF3, 1454, + 0xF2, 1448, + 0x66, 1442, + 0x0, 1436, + /*1436*/ uint16(xSetOp), uint16(MOVUPS), + /*1438*/ uint16(xReadSlashR), + /*1439*/ uint16(xArgXmm1), + /*1440*/ uint16(xArgXmm2M128), + /*1441*/ uint16(xMatch), + /*1442*/ uint16(xSetOp), uint16(MOVUPD), + /*1444*/ uint16(xReadSlashR), + /*1445*/ uint16(xArgXmm1), + /*1446*/ uint16(xArgXmm2M128), + /*1447*/ uint16(xMatch), + /*1448*/ uint16(xSetOp), uint16(MOVSD_XMM), + /*1450*/ uint16(xReadSlashR), + /*1451*/ uint16(xArgXmm1), + /*1452*/ uint16(xArgXmm2M64), + /*1453*/ uint16(xMatch), + /*1454*/ uint16(xSetOp), uint16(MOVSS), + /*1456*/ uint16(xReadSlashR), + /*1457*/ uint16(xArgXmm1), + /*1458*/ uint16(xArgXmm2M32), + /*1459*/ uint16(xMatch), + /*1460*/ uint16(xCondPrefix), 4, + 0xF3, 1488, + 0xF2, 1482, + 0x66, 1476, + 0x0, 1470, + /*1470*/ uint16(xSetOp), uint16(MOVUPS), + /*1472*/ uint16(xReadSlashR), + /*1473*/ uint16(xArgXmm2M128), + /*1474*/ uint16(xArgXmm1), + /*1475*/ uint16(xMatch), + /*1476*/ uint16(xSetOp), uint16(MOVUPD), + /*1478*/ uint16(xReadSlashR), + /*1479*/ uint16(xArgXmm2M128), + /*1480*/ uint16(xArgXmm), + /*1481*/ uint16(xMatch), + /*1482*/ uint16(xSetOp), uint16(MOVSD_XMM), + /*1484*/ uint16(xReadSlashR), + /*1485*/ uint16(xArgXmm2M64), + /*1486*/ uint16(xArgXmm1), + /*1487*/ uint16(xMatch), + /*1488*/ uint16(xSetOp), uint16(MOVSS), + /*1490*/ uint16(xReadSlashR), + /*1491*/ uint16(xArgXmm2M32), + /*1492*/ uint16(xArgXmm), + /*1493*/ uint16(xMatch), + /*1494*/ uint16(xCondPrefix), 4, + 0xF3, 1531, + 0xF2, 1525, + 0x66, 1519, + 0x0, 1504, + /*1504*/ uint16(xCondIsMem), 1507, 1513, + /*1507*/ uint16(xSetOp), uint16(MOVHLPS), + /*1509*/ uint16(xReadSlashR), + /*1510*/ uint16(xArgXmm1), + /*1511*/ uint16(xArgXmm2), + /*1512*/ uint16(xMatch), + /*1513*/ uint16(xSetOp), uint16(MOVLPS), + /*1515*/ uint16(xReadSlashR), + /*1516*/ uint16(xArgXmm), + /*1517*/ uint16(xArgM64), + /*1518*/ uint16(xMatch), + /*1519*/ uint16(xSetOp), uint16(MOVLPD), + /*1521*/ uint16(xReadSlashR), + /*1522*/ uint16(xArgXmm), + /*1523*/ uint16(xArgXmm2M64), + /*1524*/ uint16(xMatch), + /*1525*/ uint16(xSetOp), uint16(MOVDDUP), + /*1527*/ uint16(xReadSlashR), + /*1528*/ uint16(xArgXmm1), + /*1529*/ uint16(xArgXmm2M64), + /*1530*/ uint16(xMatch), + /*1531*/ uint16(xSetOp), uint16(MOVSLDUP), + /*1533*/ uint16(xReadSlashR), + /*1534*/ uint16(xArgXmm1), + /*1535*/ uint16(xArgXmm2M128), + /*1536*/ uint16(xMatch), + /*1537*/ uint16(xCondPrefix), 2, + 0x66, 1549, + 0x0, 1543, + /*1543*/ uint16(xSetOp), uint16(MOVLPS), + /*1545*/ uint16(xReadSlashR), + /*1546*/ uint16(xArgM64), + /*1547*/ uint16(xArgXmm), + /*1548*/ uint16(xMatch), + /*1549*/ uint16(xSetOp), uint16(MOVLPD), + /*1551*/ uint16(xReadSlashR), + /*1552*/ uint16(xArgXmm2M64), + /*1553*/ uint16(xArgXmm), + /*1554*/ uint16(xMatch), + /*1555*/ uint16(xCondPrefix), 2, + 0x66, 1567, + 0x0, 1561, + /*1561*/ uint16(xSetOp), uint16(UNPCKLPS), + /*1563*/ uint16(xReadSlashR), + /*1564*/ uint16(xArgXmm1), + /*1565*/ uint16(xArgXmm2M128), + /*1566*/ uint16(xMatch), + /*1567*/ uint16(xSetOp), uint16(UNPCKLPD), + /*1569*/ uint16(xReadSlashR), + /*1570*/ uint16(xArgXmm1), + /*1571*/ uint16(xArgXmm2M128), + /*1572*/ uint16(xMatch), + /*1573*/ uint16(xCondPrefix), 2, + 0x66, 1585, + 0x0, 1579, + /*1579*/ uint16(xSetOp), uint16(UNPCKHPS), + /*1581*/ uint16(xReadSlashR), + /*1582*/ uint16(xArgXmm1), + /*1583*/ uint16(xArgXmm2M128), + /*1584*/ uint16(xMatch), + /*1585*/ uint16(xSetOp), uint16(UNPCKHPD), + /*1587*/ uint16(xReadSlashR), + /*1588*/ uint16(xArgXmm1), + /*1589*/ uint16(xArgXmm2M128), + /*1590*/ uint16(xMatch), + /*1591*/ uint16(xCondPrefix), 3, + 0xF3, 1620, + 0x66, 1614, + 0x0, 1599, + /*1599*/ uint16(xCondIsMem), 1602, 1608, + /*1602*/ uint16(xSetOp), uint16(MOVLHPS), + /*1604*/ uint16(xReadSlashR), + /*1605*/ uint16(xArgXmm1), + /*1606*/ uint16(xArgXmm2), + /*1607*/ uint16(xMatch), + /*1608*/ uint16(xSetOp), uint16(MOVHPS), + /*1610*/ uint16(xReadSlashR), + /*1611*/ uint16(xArgXmm), + /*1612*/ uint16(xArgM64), + /*1613*/ uint16(xMatch), + /*1614*/ uint16(xSetOp), uint16(MOVHPD), + /*1616*/ uint16(xReadSlashR), + /*1617*/ uint16(xArgXmm), + /*1618*/ uint16(xArgXmm2M64), + /*1619*/ uint16(xMatch), + /*1620*/ uint16(xSetOp), uint16(MOVSHDUP), + /*1622*/ uint16(xReadSlashR), + /*1623*/ uint16(xArgXmm1), + /*1624*/ uint16(xArgXmm2M128), + /*1625*/ uint16(xMatch), + /*1626*/ uint16(xCondPrefix), 2, + 0x66, 1638, + 0x0, 1632, + /*1632*/ uint16(xSetOp), uint16(MOVHPS), + /*1634*/ uint16(xReadSlashR), + /*1635*/ uint16(xArgM64), + /*1636*/ uint16(xArgXmm), + /*1637*/ uint16(xMatch), + /*1638*/ uint16(xSetOp), uint16(MOVHPD), + /*1640*/ uint16(xReadSlashR), + /*1641*/ uint16(xArgXmm2M64), + /*1642*/ uint16(xArgXmm), + /*1643*/ uint16(xMatch), + /*1644*/ uint16(xCondSlashR), + 1653, // 0 + 1657, // 1 + 1661, // 2 + 1665, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*1653*/ uint16(xSetOp), uint16(PREFETCHNTA), + /*1655*/ uint16(xArgM8), + /*1656*/ uint16(xMatch), + /*1657*/ uint16(xSetOp), uint16(PREFETCHT0), + /*1659*/ uint16(xArgM8), + /*1660*/ uint16(xMatch), + /*1661*/ uint16(xSetOp), uint16(PREFETCHT1), + /*1663*/ uint16(xArgM8), + /*1664*/ uint16(xMatch), + /*1665*/ uint16(xSetOp), uint16(PREFETCHT2), + /*1667*/ uint16(xArgM8), + /*1668*/ uint16(xMatch), + /*1669*/ uint16(xCondSlashR), + 1678, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*1678*/ uint16(xCondDataSize), 1682, 1686, 0, + /*1682*/ uint16(xSetOp), uint16(NOP), + /*1684*/ uint16(xArgRM16), + /*1685*/ uint16(xMatch), + /*1686*/ uint16(xSetOp), uint16(NOP), + /*1688*/ uint16(xArgRM32), + /*1689*/ uint16(xMatch), + /*1690*/ uint16(xCondIs64), 1693, 1699, + /*1693*/ uint16(xSetOp), uint16(MOV), + /*1695*/ uint16(xReadSlashR), + /*1696*/ uint16(xArgRmf32), + /*1697*/ uint16(xArgCR0dashCR7), + /*1698*/ uint16(xMatch), + /*1699*/ uint16(xSetOp), uint16(MOV), + /*1701*/ uint16(xReadSlashR), + /*1702*/ uint16(xArgRmf64), + /*1703*/ uint16(xArgCR0dashCR7), + /*1704*/ uint16(xMatch), + /*1705*/ uint16(xCondIs64), 1708, 1714, + /*1708*/ uint16(xSetOp), uint16(MOV), + /*1710*/ uint16(xReadSlashR), + /*1711*/ uint16(xArgRmf32), + /*1712*/ uint16(xArgDR0dashDR7), + /*1713*/ uint16(xMatch), + /*1714*/ uint16(xSetOp), uint16(MOV), + /*1716*/ uint16(xReadSlashR), + /*1717*/ uint16(xArgRmf64), + /*1718*/ uint16(xArgDR0dashDR7), + /*1719*/ uint16(xMatch), + /*1720*/ uint16(xCondIs64), 1723, 1729, + /*1723*/ uint16(xSetOp), uint16(MOV), + /*1725*/ uint16(xReadSlashR), + /*1726*/ uint16(xArgCR0dashCR7), + /*1727*/ uint16(xArgRmf32), + /*1728*/ uint16(xMatch), + /*1729*/ uint16(xSetOp), uint16(MOV), + /*1731*/ uint16(xReadSlashR), + /*1732*/ uint16(xArgCR0dashCR7), + /*1733*/ uint16(xArgRmf64), + /*1734*/ uint16(xMatch), + /*1735*/ uint16(xCondIs64), 1738, 1744, + /*1738*/ uint16(xSetOp), uint16(MOV), + /*1740*/ uint16(xReadSlashR), + /*1741*/ uint16(xArgDR0dashDR7), + /*1742*/ uint16(xArgRmf32), + /*1743*/ uint16(xMatch), + /*1744*/ uint16(xSetOp), uint16(MOV), + /*1746*/ uint16(xReadSlashR), + /*1747*/ uint16(xArgDR0dashDR7), + /*1748*/ uint16(xArgRmf64), + /*1749*/ uint16(xMatch), + /*1750*/ uint16(xCondIs64), 1753, 1759, + /*1753*/ uint16(xSetOp), uint16(MOV), + /*1755*/ uint16(xReadSlashR), + /*1756*/ uint16(xArgRmf32), + /*1757*/ uint16(xArgTR0dashTR7), + /*1758*/ uint16(xMatch), + /*1759*/ uint16(xSetOp), uint16(MOV), + /*1761*/ uint16(xReadSlashR), + /*1762*/ uint16(xArgRmf64), + /*1763*/ uint16(xArgTR0dashTR7), + /*1764*/ uint16(xMatch), + /*1765*/ uint16(xCondIs64), 1768, 1774, + /*1768*/ uint16(xSetOp), uint16(MOV), + /*1770*/ uint16(xReadSlashR), + /*1771*/ uint16(xArgTR0dashTR7), + /*1772*/ uint16(xArgRmf32), + /*1773*/ uint16(xMatch), + /*1774*/ uint16(xSetOp), uint16(MOV), + /*1776*/ uint16(xReadSlashR), + /*1777*/ uint16(xArgTR0dashTR7), + /*1778*/ uint16(xArgRmf64), + /*1779*/ uint16(xMatch), + /*1780*/ uint16(xCondPrefix), 2, + 0x66, 1792, + 0x0, 1786, + /*1786*/ uint16(xSetOp), uint16(MOVAPS), + /*1788*/ uint16(xReadSlashR), + /*1789*/ uint16(xArgXmm1), + /*1790*/ uint16(xArgXmm2M128), + /*1791*/ uint16(xMatch), + /*1792*/ uint16(xSetOp), uint16(MOVAPD), + /*1794*/ uint16(xReadSlashR), + /*1795*/ uint16(xArgXmm1), + /*1796*/ uint16(xArgXmm2M128), + /*1797*/ uint16(xMatch), + /*1798*/ uint16(xCondPrefix), 2, + 0x66, 1810, + 0x0, 1804, + /*1804*/ uint16(xSetOp), uint16(MOVAPS), + /*1806*/ uint16(xReadSlashR), + /*1807*/ uint16(xArgXmm2M128), + /*1808*/ uint16(xArgXmm1), + /*1809*/ uint16(xMatch), + /*1810*/ uint16(xSetOp), uint16(MOVAPD), + /*1812*/ uint16(xReadSlashR), + /*1813*/ uint16(xArgXmm2M128), + /*1814*/ uint16(xArgXmm1), + /*1815*/ uint16(xMatch), + /*1816*/ uint16(xCondIs64), 1819, 1873, + /*1819*/ uint16(xCondPrefix), 4, + 0xF3, 1857, + 0xF2, 1841, + 0x66, 1835, + 0x0, 1829, + /*1829*/ uint16(xSetOp), uint16(CVTPI2PS), + /*1831*/ uint16(xReadSlashR), + /*1832*/ uint16(xArgXmm), + /*1833*/ uint16(xArgMmM64), + /*1834*/ uint16(xMatch), + /*1835*/ uint16(xSetOp), uint16(CVTPI2PD), + /*1837*/ uint16(xReadSlashR), + /*1838*/ uint16(xArgXmm), + /*1839*/ uint16(xArgMmM64), + /*1840*/ uint16(xMatch), + /*1841*/ uint16(xCondDataSize), 1845, 1851, 0, + /*1845*/ uint16(xSetOp), uint16(CVTSI2SD), + /*1847*/ uint16(xReadSlashR), + /*1848*/ uint16(xArgXmm), + /*1849*/ uint16(xArgRM32), + /*1850*/ uint16(xMatch), + /*1851*/ uint16(xSetOp), uint16(CVTSI2SD), + /*1853*/ uint16(xReadSlashR), + /*1854*/ uint16(xArgXmm), + /*1855*/ uint16(xArgRM32), + /*1856*/ uint16(xMatch), + /*1857*/ uint16(xCondDataSize), 1861, 1867, 0, + /*1861*/ uint16(xSetOp), uint16(CVTSI2SS), + /*1863*/ uint16(xReadSlashR), + /*1864*/ uint16(xArgXmm), + /*1865*/ uint16(xArgRM32), + /*1866*/ uint16(xMatch), + /*1867*/ uint16(xSetOp), uint16(CVTSI2SS), + /*1869*/ uint16(xReadSlashR), + /*1870*/ uint16(xArgXmm), + /*1871*/ uint16(xArgRM32), + /*1872*/ uint16(xMatch), + /*1873*/ uint16(xCondPrefix), 4, + 0xF3, 1893, + 0xF2, 1883, + 0x66, 1835, + 0x0, 1829, + /*1883*/ uint16(xCondDataSize), 1845, 1851, 1887, + /*1887*/ uint16(xSetOp), uint16(CVTSI2SD), + /*1889*/ uint16(xReadSlashR), + /*1890*/ uint16(xArgXmm), + /*1891*/ uint16(xArgRM64), + /*1892*/ uint16(xMatch), + /*1893*/ uint16(xCondDataSize), 1861, 1867, 1897, + /*1897*/ uint16(xSetOp), uint16(CVTSI2SS), + /*1899*/ uint16(xReadSlashR), + /*1900*/ uint16(xArgXmm), + /*1901*/ uint16(xArgRM64), + /*1902*/ uint16(xMatch), + /*1903*/ uint16(xCondPrefix), 4, + 0xF3, 1931, + 0xF2, 1925, + 0x66, 1919, + 0x0, 1913, + /*1913*/ uint16(xSetOp), uint16(MOVNTPS), + /*1915*/ uint16(xReadSlashR), + /*1916*/ uint16(xArgM128), + /*1917*/ uint16(xArgXmm), + /*1918*/ uint16(xMatch), + /*1919*/ uint16(xSetOp), uint16(MOVNTPD), + /*1921*/ uint16(xReadSlashR), + /*1922*/ uint16(xArgM128), + /*1923*/ uint16(xArgXmm), + /*1924*/ uint16(xMatch), + /*1925*/ uint16(xSetOp), uint16(MOVNTSD), + /*1927*/ uint16(xReadSlashR), + /*1928*/ uint16(xArgM64), + /*1929*/ uint16(xArgXmm), + /*1930*/ uint16(xMatch), + /*1931*/ uint16(xSetOp), uint16(MOVNTSS), + /*1933*/ uint16(xReadSlashR), + /*1934*/ uint16(xArgM32), + /*1935*/ uint16(xArgXmm), + /*1936*/ uint16(xMatch), + /*1937*/ uint16(xCondIs64), 1940, 1994, + /*1940*/ uint16(xCondPrefix), 4, + 0xF3, 1978, + 0xF2, 1962, + 0x66, 1956, + 0x0, 1950, + /*1950*/ uint16(xSetOp), uint16(CVTTPS2PI), + /*1952*/ uint16(xReadSlashR), + /*1953*/ uint16(xArgMm), + /*1954*/ uint16(xArgXmmM64), + /*1955*/ uint16(xMatch), + /*1956*/ uint16(xSetOp), uint16(CVTTPD2PI), + /*1958*/ uint16(xReadSlashR), + /*1959*/ uint16(xArgMm), + /*1960*/ uint16(xArgXmmM128), + /*1961*/ uint16(xMatch), + /*1962*/ uint16(xCondDataSize), 1966, 1972, 0, + /*1966*/ uint16(xSetOp), uint16(CVTTSD2SI), + /*1968*/ uint16(xReadSlashR), + /*1969*/ uint16(xArgR32), + /*1970*/ uint16(xArgXmmM64), + /*1971*/ uint16(xMatch), + /*1972*/ uint16(xSetOp), uint16(CVTTSD2SI), + /*1974*/ uint16(xReadSlashR), + /*1975*/ uint16(xArgR32), + /*1976*/ uint16(xArgXmmM64), + /*1977*/ uint16(xMatch), + /*1978*/ uint16(xCondDataSize), 1982, 1988, 0, + /*1982*/ uint16(xSetOp), uint16(CVTTSS2SI), + /*1984*/ uint16(xReadSlashR), + /*1985*/ uint16(xArgR32), + /*1986*/ uint16(xArgXmmM32), + /*1987*/ uint16(xMatch), + /*1988*/ uint16(xSetOp), uint16(CVTTSS2SI), + /*1990*/ uint16(xReadSlashR), + /*1991*/ uint16(xArgR32), + /*1992*/ uint16(xArgXmmM32), + /*1993*/ uint16(xMatch), + /*1994*/ uint16(xCondPrefix), 4, + 0xF3, 2014, + 0xF2, 2004, + 0x66, 1956, + 0x0, 1950, + /*2004*/ uint16(xCondDataSize), 1966, 1972, 2008, + /*2008*/ uint16(xSetOp), uint16(CVTTSD2SI), + /*2010*/ uint16(xReadSlashR), + /*2011*/ uint16(xArgR64), + /*2012*/ uint16(xArgXmmM64), + /*2013*/ uint16(xMatch), + /*2014*/ uint16(xCondDataSize), 1982, 1988, 2018, + /*2018*/ uint16(xSetOp), uint16(CVTTSS2SI), + /*2020*/ uint16(xReadSlashR), + /*2021*/ uint16(xArgR64), + /*2022*/ uint16(xArgXmmM32), + /*2023*/ uint16(xMatch), + /*2024*/ uint16(xCondIs64), 2027, 2081, + /*2027*/ uint16(xCondPrefix), 4, + 0xF3, 2065, + 0xF2, 2049, + 0x66, 2043, + 0x0, 2037, + /*2037*/ uint16(xSetOp), uint16(CVTPS2PI), + /*2039*/ uint16(xReadSlashR), + /*2040*/ uint16(xArgMm), + /*2041*/ uint16(xArgXmmM64), + /*2042*/ uint16(xMatch), + /*2043*/ uint16(xSetOp), uint16(CVTPD2PI), + /*2045*/ uint16(xReadSlashR), + /*2046*/ uint16(xArgMm), + /*2047*/ uint16(xArgXmmM128), + /*2048*/ uint16(xMatch), + /*2049*/ uint16(xCondDataSize), 2053, 2059, 0, + /*2053*/ uint16(xSetOp), uint16(CVTSD2SI), + /*2055*/ uint16(xReadSlashR), + /*2056*/ uint16(xArgR32), + /*2057*/ uint16(xArgXmmM64), + /*2058*/ uint16(xMatch), + /*2059*/ uint16(xSetOp), uint16(CVTSD2SI), + /*2061*/ uint16(xReadSlashR), + /*2062*/ uint16(xArgR32), + /*2063*/ uint16(xArgXmmM64), + /*2064*/ uint16(xMatch), + /*2065*/ uint16(xCondDataSize), 2069, 2075, 0, + /*2069*/ uint16(xSetOp), uint16(CVTSS2SI), + /*2071*/ uint16(xReadSlashR), + /*2072*/ uint16(xArgR32), + /*2073*/ uint16(xArgXmmM32), + /*2074*/ uint16(xMatch), + /*2075*/ uint16(xSetOp), uint16(CVTSS2SI), + /*2077*/ uint16(xReadSlashR), + /*2078*/ uint16(xArgR32), + /*2079*/ uint16(xArgXmmM32), + /*2080*/ uint16(xMatch), + /*2081*/ uint16(xCondPrefix), 4, + 0xF3, 2101, + 0xF2, 2091, + 0x66, 2043, + 0x0, 2037, + /*2091*/ uint16(xCondDataSize), 2053, 2059, 2095, + /*2095*/ uint16(xSetOp), uint16(CVTSD2SI), + /*2097*/ uint16(xReadSlashR), + /*2098*/ uint16(xArgR64), + /*2099*/ uint16(xArgXmmM64), + /*2100*/ uint16(xMatch), + /*2101*/ uint16(xCondDataSize), 2069, 2075, 2105, + /*2105*/ uint16(xSetOp), uint16(CVTSS2SI), + /*2107*/ uint16(xReadSlashR), + /*2108*/ uint16(xArgR64), + /*2109*/ uint16(xArgXmmM32), + /*2110*/ uint16(xMatch), + /*2111*/ uint16(xCondPrefix), 2, + 0x66, 2123, + 0x0, 2117, + /*2117*/ uint16(xSetOp), uint16(UCOMISS), + /*2119*/ uint16(xReadSlashR), + /*2120*/ uint16(xArgXmm1), + /*2121*/ uint16(xArgXmm2M32), + /*2122*/ uint16(xMatch), + /*2123*/ uint16(xSetOp), uint16(UCOMISD), + /*2125*/ uint16(xReadSlashR), + /*2126*/ uint16(xArgXmm1), + /*2127*/ uint16(xArgXmm2M64), + /*2128*/ uint16(xMatch), + /*2129*/ uint16(xCondPrefix), 2, + 0x66, 2141, + 0x0, 2135, + /*2135*/ uint16(xSetOp), uint16(COMISS), + /*2137*/ uint16(xReadSlashR), + /*2138*/ uint16(xArgXmm1), + /*2139*/ uint16(xArgXmm2M32), + /*2140*/ uint16(xMatch), + /*2141*/ uint16(xSetOp), uint16(COMISD), + /*2143*/ uint16(xReadSlashR), + /*2144*/ uint16(xArgXmm1), + /*2145*/ uint16(xArgXmm2M64), + /*2146*/ uint16(xMatch), + /*2147*/ uint16(xSetOp), uint16(WRMSR), + /*2149*/ uint16(xMatch), + /*2150*/ uint16(xSetOp), uint16(RDTSC), + /*2152*/ uint16(xMatch), + /*2153*/ uint16(xSetOp), uint16(RDMSR), + /*2155*/ uint16(xMatch), + /*2156*/ uint16(xSetOp), uint16(RDPMC), + /*2158*/ uint16(xMatch), + /*2159*/ uint16(xSetOp), uint16(SYSENTER), + /*2161*/ uint16(xMatch), + /*2162*/ uint16(xCondDataSize), 2166, 2166, 2169, + /*2166*/ uint16(xSetOp), uint16(SYSEXIT), + /*2168*/ uint16(xMatch), + /*2169*/ uint16(xSetOp), uint16(SYSEXIT), + /*2171*/ uint16(xMatch), + /*2172*/ uint16(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(xFail), + /*2283*/ uint16(xCondPrefix), 2, + 0x66, 2295, + 0x0, 2289, + /*2289*/ uint16(xSetOp), uint16(PSHUFB), + /*2291*/ uint16(xReadSlashR), + /*2292*/ uint16(xArgMm1), + /*2293*/ uint16(xArgMm2M64), + /*2294*/ uint16(xMatch), + /*2295*/ uint16(xSetOp), uint16(PSHUFB), + /*2297*/ uint16(xReadSlashR), + /*2298*/ uint16(xArgXmm1), + /*2299*/ uint16(xArgXmm2M128), + /*2300*/ uint16(xMatch), + /*2301*/ uint16(xCondPrefix), 2, + 0x66, 2313, + 0x0, 2307, + /*2307*/ uint16(xSetOp), uint16(PHADDW), + /*2309*/ uint16(xReadSlashR), + /*2310*/ uint16(xArgMm1), + /*2311*/ uint16(xArgMm2M64), + /*2312*/ uint16(xMatch), + /*2313*/ uint16(xSetOp), uint16(PHADDW), + /*2315*/ uint16(xReadSlashR), + /*2316*/ uint16(xArgXmm1), + /*2317*/ uint16(xArgXmm2M128), + /*2318*/ uint16(xMatch), + /*2319*/ uint16(xCondPrefix), 2, + 0x66, 2331, + 0x0, 2325, + /*2325*/ uint16(xSetOp), uint16(PHADDD), + /*2327*/ uint16(xReadSlashR), + /*2328*/ uint16(xArgMm1), + /*2329*/ uint16(xArgMm2M64), + /*2330*/ uint16(xMatch), + /*2331*/ uint16(xSetOp), uint16(PHADDD), + /*2333*/ uint16(xReadSlashR), + /*2334*/ uint16(xArgXmm1), + /*2335*/ uint16(xArgXmm2M128), + /*2336*/ uint16(xMatch), + /*2337*/ uint16(xCondPrefix), 2, + 0x66, 2349, + 0x0, 2343, + /*2343*/ uint16(xSetOp), uint16(PHADDSW), + /*2345*/ uint16(xReadSlashR), + /*2346*/ uint16(xArgMm1), + /*2347*/ uint16(xArgMm2M64), + /*2348*/ uint16(xMatch), + /*2349*/ uint16(xSetOp), uint16(PHADDSW), + /*2351*/ uint16(xReadSlashR), + /*2352*/ uint16(xArgXmm1), + /*2353*/ uint16(xArgXmm2M128), + /*2354*/ uint16(xMatch), + /*2355*/ uint16(xCondPrefix), 2, + 0x66, 2367, + 0x0, 2361, + /*2361*/ uint16(xSetOp), uint16(PMADDUBSW), + /*2363*/ uint16(xReadSlashR), + /*2364*/ uint16(xArgMm1), + /*2365*/ uint16(xArgMm2M64), + /*2366*/ uint16(xMatch), + /*2367*/ uint16(xSetOp), uint16(PMADDUBSW), + /*2369*/ uint16(xReadSlashR), + /*2370*/ uint16(xArgXmm1), + /*2371*/ uint16(xArgXmm2M128), + /*2372*/ uint16(xMatch), + /*2373*/ uint16(xCondPrefix), 2, + 0x66, 2385, + 0x0, 2379, + /*2379*/ uint16(xSetOp), uint16(PHSUBW), + /*2381*/ uint16(xReadSlashR), + /*2382*/ uint16(xArgMm1), + /*2383*/ uint16(xArgMm2M64), + /*2384*/ uint16(xMatch), + /*2385*/ uint16(xSetOp), uint16(PHSUBW), + /*2387*/ uint16(xReadSlashR), + /*2388*/ uint16(xArgXmm1), + /*2389*/ uint16(xArgXmm2M128), + /*2390*/ uint16(xMatch), + /*2391*/ uint16(xCondPrefix), 2, + 0x66, 2403, + 0x0, 2397, + /*2397*/ uint16(xSetOp), uint16(PHSUBD), + /*2399*/ uint16(xReadSlashR), + /*2400*/ uint16(xArgMm1), + /*2401*/ uint16(xArgMm2M64), + /*2402*/ uint16(xMatch), + /*2403*/ uint16(xSetOp), uint16(PHSUBD), + /*2405*/ uint16(xReadSlashR), + /*2406*/ uint16(xArgXmm1), + /*2407*/ uint16(xArgXmm2M128), + /*2408*/ uint16(xMatch), + /*2409*/ uint16(xCondPrefix), 2, + 0x66, 2421, + 0x0, 2415, + /*2415*/ uint16(xSetOp), uint16(PHSUBSW), + /*2417*/ uint16(xReadSlashR), + /*2418*/ uint16(xArgMm1), + /*2419*/ uint16(xArgMm2M64), + /*2420*/ uint16(xMatch), + /*2421*/ uint16(xSetOp), uint16(PHSUBSW), + /*2423*/ uint16(xReadSlashR), + /*2424*/ uint16(xArgXmm1), + /*2425*/ uint16(xArgXmm2M128), + /*2426*/ uint16(xMatch), + /*2427*/ uint16(xCondPrefix), 2, + 0x66, 2439, + 0x0, 2433, + /*2433*/ uint16(xSetOp), uint16(PSIGNB), + /*2435*/ uint16(xReadSlashR), + /*2436*/ uint16(xArgMm1), + /*2437*/ uint16(xArgMm2M64), + /*2438*/ uint16(xMatch), + /*2439*/ uint16(xSetOp), uint16(PSIGNB), + /*2441*/ uint16(xReadSlashR), + /*2442*/ uint16(xArgXmm1), + /*2443*/ uint16(xArgXmm2M128), + /*2444*/ uint16(xMatch), + /*2445*/ uint16(xCondPrefix), 2, + 0x66, 2457, + 0x0, 2451, + /*2451*/ uint16(xSetOp), uint16(PSIGNW), + /*2453*/ uint16(xReadSlashR), + /*2454*/ uint16(xArgMm1), + /*2455*/ uint16(xArgMm2M64), + /*2456*/ uint16(xMatch), + /*2457*/ uint16(xSetOp), uint16(PSIGNW), + /*2459*/ uint16(xReadSlashR), + /*2460*/ uint16(xArgXmm1), + /*2461*/ uint16(xArgXmm2M128), + /*2462*/ uint16(xMatch), + /*2463*/ uint16(xCondPrefix), 2, + 0x66, 2475, + 0x0, 2469, + /*2469*/ uint16(xSetOp), uint16(PSIGND), + /*2471*/ uint16(xReadSlashR), + /*2472*/ uint16(xArgMm1), + /*2473*/ uint16(xArgMm2M64), + /*2474*/ uint16(xMatch), + /*2475*/ uint16(xSetOp), uint16(PSIGND), + /*2477*/ uint16(xReadSlashR), + /*2478*/ uint16(xArgXmm1), + /*2479*/ uint16(xArgXmm2M128), + /*2480*/ uint16(xMatch), + /*2481*/ uint16(xCondPrefix), 2, + 0x66, 2493, + 0x0, 2487, + /*2487*/ uint16(xSetOp), uint16(PMULHRSW), + /*2489*/ uint16(xReadSlashR), + /*2490*/ uint16(xArgMm1), + /*2491*/ uint16(xArgMm2M64), + /*2492*/ uint16(xMatch), + /*2493*/ uint16(xSetOp), uint16(PMULHRSW), + /*2495*/ uint16(xReadSlashR), + /*2496*/ uint16(xArgXmm1), + /*2497*/ uint16(xArgXmm2M128), + /*2498*/ uint16(xMatch), + /*2499*/ uint16(xCondPrefix), 1, + 0x66, 2503, + /*2503*/ uint16(xSetOp), uint16(PBLENDVB), + /*2505*/ uint16(xReadSlashR), + /*2506*/ uint16(xArgXmm1), + /*2507*/ uint16(xArgXmm2M128), + /*2508*/ uint16(xArgXMM0), + /*2509*/ uint16(xMatch), + /*2510*/ uint16(xCondPrefix), 1, + 0x66, 2514, + /*2514*/ uint16(xSetOp), uint16(BLENDVPS), + /*2516*/ uint16(xReadSlashR), + /*2517*/ uint16(xArgXmm1), + /*2518*/ uint16(xArgXmm2M128), + /*2519*/ uint16(xArgXMM0), + /*2520*/ uint16(xMatch), + /*2521*/ uint16(xCondPrefix), 1, + 0x66, 2525, + /*2525*/ uint16(xSetOp), uint16(BLENDVPD), + /*2527*/ uint16(xReadSlashR), + /*2528*/ uint16(xArgXmm1), + /*2529*/ uint16(xArgXmm2M128), + /*2530*/ uint16(xArgXMM0), + /*2531*/ uint16(xMatch), + /*2532*/ uint16(xCondPrefix), 1, + 0x66, 2536, + /*2536*/ uint16(xSetOp), uint16(PTEST), + /*2538*/ uint16(xReadSlashR), + /*2539*/ uint16(xArgXmm1), + /*2540*/ uint16(xArgXmm2M128), + /*2541*/ uint16(xMatch), + /*2542*/ uint16(xCondPrefix), 2, + 0x66, 2554, + 0x0, 2548, + /*2548*/ uint16(xSetOp), uint16(PABSB), + /*2550*/ uint16(xReadSlashR), + /*2551*/ uint16(xArgMm1), + /*2552*/ uint16(xArgMm2M64), + /*2553*/ uint16(xMatch), + /*2554*/ uint16(xSetOp), uint16(PABSB), + /*2556*/ uint16(xReadSlashR), + /*2557*/ uint16(xArgXmm1), + /*2558*/ uint16(xArgXmm2M128), + /*2559*/ uint16(xMatch), + /*2560*/ uint16(xCondPrefix), 2, + 0x66, 2572, + 0x0, 2566, + /*2566*/ uint16(xSetOp), uint16(PABSW), + /*2568*/ uint16(xReadSlashR), + /*2569*/ uint16(xArgMm1), + /*2570*/ uint16(xArgMm2M64), + /*2571*/ uint16(xMatch), + /*2572*/ uint16(xSetOp), uint16(PABSW), + /*2574*/ uint16(xReadSlashR), + /*2575*/ uint16(xArgXmm1), + /*2576*/ uint16(xArgXmm2M128), + /*2577*/ uint16(xMatch), + /*2578*/ uint16(xCondPrefix), 2, + 0x66, 2590, + 0x0, 2584, + /*2584*/ uint16(xSetOp), uint16(PABSD), + /*2586*/ uint16(xReadSlashR), + /*2587*/ uint16(xArgMm1), + /*2588*/ uint16(xArgMm2M64), + /*2589*/ uint16(xMatch), + /*2590*/ uint16(xSetOp), uint16(PABSD), + /*2592*/ uint16(xReadSlashR), + /*2593*/ uint16(xArgXmm1), + /*2594*/ uint16(xArgXmm2M128), + /*2595*/ uint16(xMatch), + /*2596*/ uint16(xCondPrefix), 1, + 0x66, 2600, + /*2600*/ uint16(xSetOp), uint16(PMOVSXBW), + /*2602*/ uint16(xReadSlashR), + /*2603*/ uint16(xArgXmm1), + /*2604*/ uint16(xArgXmm2M64), + /*2605*/ uint16(xMatch), + /*2606*/ uint16(xCondPrefix), 1, + 0x66, 2610, + /*2610*/ uint16(xSetOp), uint16(PMOVSXBD), + /*2612*/ uint16(xReadSlashR), + /*2613*/ uint16(xArgXmm1), + /*2614*/ uint16(xArgXmm2M32), + /*2615*/ uint16(xMatch), + /*2616*/ uint16(xCondPrefix), 1, + 0x66, 2620, + /*2620*/ uint16(xSetOp), uint16(PMOVSXBQ), + /*2622*/ uint16(xReadSlashR), + /*2623*/ uint16(xArgXmm1), + /*2624*/ uint16(xArgXmm2M16), + /*2625*/ uint16(xMatch), + /*2626*/ uint16(xCondPrefix), 1, + 0x66, 2630, + /*2630*/ uint16(xSetOp), uint16(PMOVSXWD), + /*2632*/ uint16(xReadSlashR), + /*2633*/ uint16(xArgXmm1), + /*2634*/ uint16(xArgXmm2M64), + /*2635*/ uint16(xMatch), + /*2636*/ uint16(xCondPrefix), 1, + 0x66, 2640, + /*2640*/ uint16(xSetOp), uint16(PMOVSXWQ), + /*2642*/ uint16(xReadSlashR), + /*2643*/ uint16(xArgXmm1), + /*2644*/ uint16(xArgXmm2M32), + /*2645*/ uint16(xMatch), + /*2646*/ uint16(xCondPrefix), 1, + 0x66, 2650, + /*2650*/ uint16(xSetOp), uint16(PMOVSXDQ), + /*2652*/ uint16(xReadSlashR), + /*2653*/ uint16(xArgXmm1), + /*2654*/ uint16(xArgXmm2M64), + /*2655*/ uint16(xMatch), + /*2656*/ uint16(xCondPrefix), 1, + 0x66, 2660, + /*2660*/ uint16(xSetOp), uint16(PMULDQ), + /*2662*/ uint16(xReadSlashR), + /*2663*/ uint16(xArgXmm1), + /*2664*/ uint16(xArgXmm2M128), + /*2665*/ uint16(xMatch), + /*2666*/ uint16(xCondPrefix), 1, + 0x66, 2670, + /*2670*/ uint16(xSetOp), uint16(PCMPEQQ), + /*2672*/ uint16(xReadSlashR), + /*2673*/ uint16(xArgXmm1), + /*2674*/ uint16(xArgXmm2M128), + /*2675*/ uint16(xMatch), + /*2676*/ uint16(xCondPrefix), 1, + 0x66, 2680, + /*2680*/ uint16(xSetOp), uint16(MOVNTDQA), + /*2682*/ uint16(xReadSlashR), + /*2683*/ uint16(xArgXmm1), + /*2684*/ uint16(xArgM128), + /*2685*/ uint16(xMatch), + /*2686*/ uint16(xCondPrefix), 1, + 0x66, 2690, + /*2690*/ uint16(xSetOp), uint16(PACKUSDW), + /*2692*/ uint16(xReadSlashR), + /*2693*/ uint16(xArgXmm1), + /*2694*/ uint16(xArgXmm2M128), + /*2695*/ uint16(xMatch), + /*2696*/ uint16(xCondPrefix), 1, + 0x66, 2700, + /*2700*/ uint16(xSetOp), uint16(PMOVZXBW), + /*2702*/ uint16(xReadSlashR), + /*2703*/ uint16(xArgXmm1), + /*2704*/ uint16(xArgXmm2M64), + /*2705*/ uint16(xMatch), + /*2706*/ uint16(xCondPrefix), 1, + 0x66, 2710, + /*2710*/ uint16(xSetOp), uint16(PMOVZXBD), + /*2712*/ uint16(xReadSlashR), + /*2713*/ uint16(xArgXmm1), + /*2714*/ uint16(xArgXmm2M32), + /*2715*/ uint16(xMatch), + /*2716*/ uint16(xCondPrefix), 1, + 0x66, 2720, + /*2720*/ uint16(xSetOp), uint16(PMOVZXBQ), + /*2722*/ uint16(xReadSlashR), + /*2723*/ uint16(xArgXmm1), + /*2724*/ uint16(xArgXmm2M16), + /*2725*/ uint16(xMatch), + /*2726*/ uint16(xCondPrefix), 1, + 0x66, 2730, + /*2730*/ uint16(xSetOp), uint16(PMOVZXWD), + /*2732*/ uint16(xReadSlashR), + /*2733*/ uint16(xArgXmm1), + /*2734*/ uint16(xArgXmm2M64), + /*2735*/ uint16(xMatch), + /*2736*/ uint16(xCondPrefix), 1, + 0x66, 2740, + /*2740*/ uint16(xSetOp), uint16(PMOVZXWQ), + /*2742*/ uint16(xReadSlashR), + /*2743*/ uint16(xArgXmm1), + /*2744*/ uint16(xArgXmm2M32), + /*2745*/ uint16(xMatch), + /*2746*/ uint16(xCondPrefix), 1, + 0x66, 2750, + /*2750*/ uint16(xSetOp), uint16(PMOVZXDQ), + /*2752*/ uint16(xReadSlashR), + /*2753*/ uint16(xArgXmm1), + /*2754*/ uint16(xArgXmm2M64), + /*2755*/ uint16(xMatch), + /*2756*/ uint16(xCondPrefix), 1, + 0x66, 2760, + /*2760*/ uint16(xSetOp), uint16(PCMPGTQ), + /*2762*/ uint16(xReadSlashR), + /*2763*/ uint16(xArgXmm1), + /*2764*/ uint16(xArgXmm2M128), + /*2765*/ uint16(xMatch), + /*2766*/ uint16(xCondPrefix), 1, + 0x66, 2770, + /*2770*/ uint16(xSetOp), uint16(PMINSB), + /*2772*/ uint16(xReadSlashR), + /*2773*/ uint16(xArgXmm1), + /*2774*/ uint16(xArgXmm2M128), + /*2775*/ uint16(xMatch), + /*2776*/ uint16(xCondPrefix), 1, + 0x66, 2780, + /*2780*/ uint16(xSetOp), uint16(PMINSD), + /*2782*/ uint16(xReadSlashR), + /*2783*/ uint16(xArgXmm1), + /*2784*/ uint16(xArgXmm2M128), + /*2785*/ uint16(xMatch), + /*2786*/ uint16(xCondPrefix), 1, + 0x66, 2790, + /*2790*/ uint16(xSetOp), uint16(PMINUW), + /*2792*/ uint16(xReadSlashR), + /*2793*/ uint16(xArgXmm1), + /*2794*/ uint16(xArgXmm2M128), + /*2795*/ uint16(xMatch), + /*2796*/ uint16(xCondPrefix), 1, + 0x66, 2800, + /*2800*/ uint16(xSetOp), uint16(PMINUD), + /*2802*/ uint16(xReadSlashR), + /*2803*/ uint16(xArgXmm1), + /*2804*/ uint16(xArgXmm2M128), + /*2805*/ uint16(xMatch), + /*2806*/ uint16(xCondPrefix), 1, + 0x66, 2810, + /*2810*/ uint16(xSetOp), uint16(PMAXSB), + /*2812*/ uint16(xReadSlashR), + /*2813*/ uint16(xArgXmm1), + /*2814*/ uint16(xArgXmm2M128), + /*2815*/ uint16(xMatch), + /*2816*/ uint16(xCondPrefix), 1, + 0x66, 2820, + /*2820*/ uint16(xSetOp), uint16(PMAXSD), + /*2822*/ uint16(xReadSlashR), + /*2823*/ uint16(xArgXmm1), + /*2824*/ uint16(xArgXmm2M128), + /*2825*/ uint16(xMatch), + /*2826*/ uint16(xCondPrefix), 1, + 0x66, 2830, + /*2830*/ uint16(xSetOp), uint16(PMAXUW), + /*2832*/ uint16(xReadSlashR), + /*2833*/ uint16(xArgXmm1), + /*2834*/ uint16(xArgXmm2M128), + /*2835*/ uint16(xMatch), + /*2836*/ uint16(xCondPrefix), 1, + 0x66, 2840, + /*2840*/ uint16(xSetOp), uint16(PMAXUD), + /*2842*/ uint16(xReadSlashR), + /*2843*/ uint16(xArgXmm1), + /*2844*/ uint16(xArgXmm2M128), + /*2845*/ uint16(xMatch), + /*2846*/ uint16(xCondPrefix), 1, + 0x66, 2850, + /*2850*/ uint16(xSetOp), uint16(PMULLD), + /*2852*/ uint16(xReadSlashR), + /*2853*/ uint16(xArgXmm1), + /*2854*/ uint16(xArgXmm2M128), + /*2855*/ uint16(xMatch), + /*2856*/ uint16(xCondPrefix), 1, + 0x66, 2860, + /*2860*/ uint16(xSetOp), uint16(PHMINPOSUW), + /*2862*/ uint16(xReadSlashR), + /*2863*/ uint16(xArgXmm1), + /*2864*/ uint16(xArgXmm2M128), + /*2865*/ uint16(xMatch), + /*2866*/ uint16(xCondIs64), 2869, 2879, + /*2869*/ uint16(xCondPrefix), 1, + 0x66, 2873, + /*2873*/ uint16(xSetOp), uint16(INVPCID), + /*2875*/ uint16(xReadSlashR), + /*2876*/ uint16(xArgR32), + /*2877*/ uint16(xArgM128), + /*2878*/ uint16(xMatch), + /*2879*/ uint16(xCondPrefix), 1, + 0x66, 2883, + /*2883*/ uint16(xSetOp), uint16(INVPCID), + /*2885*/ uint16(xReadSlashR), + /*2886*/ uint16(xArgR64), + /*2887*/ uint16(xArgM128), + /*2888*/ uint16(xMatch), + /*2889*/ uint16(xCondPrefix), 1, + 0x66, 2893, + /*2893*/ uint16(xSetOp), uint16(AESIMC), + /*2895*/ uint16(xReadSlashR), + /*2896*/ uint16(xArgXmm1), + /*2897*/ uint16(xArgXmm2M128), + /*2898*/ uint16(xMatch), + /*2899*/ uint16(xCondPrefix), 1, + 0x66, 2903, + /*2903*/ uint16(xSetOp), uint16(AESENC), + /*2905*/ uint16(xReadSlashR), + /*2906*/ uint16(xArgXmm1), + /*2907*/ uint16(xArgXmm2M128), + /*2908*/ uint16(xMatch), + /*2909*/ uint16(xCondPrefix), 1, + 0x66, 2913, + /*2913*/ uint16(xSetOp), uint16(AESENCLAST), + /*2915*/ uint16(xReadSlashR), + /*2916*/ uint16(xArgXmm1), + /*2917*/ uint16(xArgXmm2M128), + /*2918*/ uint16(xMatch), + /*2919*/ uint16(xCondPrefix), 1, + 0x66, 2923, + /*2923*/ uint16(xSetOp), uint16(AESDEC), + /*2925*/ uint16(xReadSlashR), + /*2926*/ uint16(xArgXmm1), + /*2927*/ uint16(xArgXmm2M128), + /*2928*/ uint16(xMatch), + /*2929*/ uint16(xCondPrefix), 1, + 0x66, 2933, + /*2933*/ uint16(xSetOp), uint16(AESDECLAST), + /*2935*/ uint16(xReadSlashR), + /*2936*/ uint16(xArgXmm1), + /*2937*/ uint16(xArgXmm2M128), + /*2938*/ uint16(xMatch), + /*2939*/ uint16(xCondIs64), 2942, 2980, + /*2942*/ uint16(xCondPrefix), 2, + 0xF2, 2964, + 0x0, 2948, + /*2948*/ uint16(xCondDataSize), 2952, 2958, 0, + /*2952*/ uint16(xSetOp), uint16(MOVBE), + /*2954*/ uint16(xReadSlashR), + /*2955*/ uint16(xArgR16), + /*2956*/ uint16(xArgM16), + /*2957*/ uint16(xMatch), + /*2958*/ uint16(xSetOp), uint16(MOVBE), + /*2960*/ uint16(xReadSlashR), + /*2961*/ uint16(xArgR32), + /*2962*/ uint16(xArgM32), + /*2963*/ uint16(xMatch), + /*2964*/ uint16(xCondDataSize), 2968, 2974, 0, + /*2968*/ uint16(xSetOp), uint16(CRC32), + /*2970*/ uint16(xReadSlashR), + /*2971*/ uint16(xArgR32), + /*2972*/ uint16(xArgRM8), + /*2973*/ uint16(xMatch), + /*2974*/ uint16(xSetOp), uint16(CRC32), + /*2976*/ uint16(xReadSlashR), + /*2977*/ uint16(xArgR32), + /*2978*/ uint16(xArgRM8), + /*2979*/ uint16(xMatch), + /*2980*/ uint16(xCondPrefix), 2, + 0xF2, 2996, + 0x0, 2986, + /*2986*/ uint16(xCondDataSize), 2952, 2958, 2990, + /*2990*/ uint16(xSetOp), uint16(MOVBE), + /*2992*/ uint16(xReadSlashR), + /*2993*/ uint16(xArgR64), + /*2994*/ uint16(xArgM64), + /*2995*/ uint16(xMatch), + /*2996*/ uint16(xCondDataSize), 2968, 2974, 3000, + /*3000*/ uint16(xSetOp), uint16(CRC32), + /*3002*/ uint16(xReadSlashR), + /*3003*/ uint16(xArgR64), + /*3004*/ uint16(xArgRM8), + /*3005*/ uint16(xMatch), + /*3006*/ uint16(xCondIs64), 3009, 3047, + /*3009*/ uint16(xCondPrefix), 2, + 0xF2, 3031, + 0x0, 3015, + /*3015*/ uint16(xCondDataSize), 3019, 3025, 0, + /*3019*/ uint16(xSetOp), uint16(MOVBE), + /*3021*/ uint16(xReadSlashR), + /*3022*/ uint16(xArgM16), + /*3023*/ uint16(xArgR16), + /*3024*/ uint16(xMatch), + /*3025*/ uint16(xSetOp), uint16(MOVBE), + /*3027*/ uint16(xReadSlashR), + /*3028*/ uint16(xArgM32), + /*3029*/ uint16(xArgR32), + /*3030*/ uint16(xMatch), + /*3031*/ uint16(xCondDataSize), 3035, 3041, 0, + /*3035*/ uint16(xSetOp), uint16(CRC32), + /*3037*/ uint16(xReadSlashR), + /*3038*/ uint16(xArgR32), + /*3039*/ uint16(xArgRM16), + /*3040*/ uint16(xMatch), + /*3041*/ uint16(xSetOp), uint16(CRC32), + /*3043*/ uint16(xReadSlashR), + /*3044*/ uint16(xArgR32), + /*3045*/ uint16(xArgRM32), + /*3046*/ uint16(xMatch), + /*3047*/ uint16(xCondPrefix), 2, + 0xF2, 3063, + 0x0, 3053, + /*3053*/ uint16(xCondDataSize), 3019, 3025, 3057, + /*3057*/ uint16(xSetOp), uint16(MOVBE), + /*3059*/ uint16(xReadSlashR), + /*3060*/ uint16(xArgM64), + /*3061*/ uint16(xArgR64), + /*3062*/ uint16(xMatch), + /*3063*/ uint16(xCondDataSize), 3035, 3041, 3067, + /*3067*/ uint16(xSetOp), uint16(CRC32), + /*3069*/ uint16(xReadSlashR), + /*3070*/ uint16(xArgR64), + /*3071*/ uint16(xArgRM64), + /*3072*/ uint16(xMatch), + /*3073*/ uint16(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(xFail), + /*3124*/ uint16(xCondPrefix), 1, + 0x66, 3128, + /*3128*/ uint16(xSetOp), uint16(ROUNDPS), + /*3130*/ uint16(xReadSlashR), + /*3131*/ uint16(xReadIb), + /*3132*/ uint16(xArgXmm1), + /*3133*/ uint16(xArgXmm2M128), + /*3134*/ uint16(xArgImm8u), + /*3135*/ uint16(xMatch), + /*3136*/ uint16(xCondPrefix), 1, + 0x66, 3140, + /*3140*/ uint16(xSetOp), uint16(ROUNDPD), + /*3142*/ uint16(xReadSlashR), + /*3143*/ uint16(xReadIb), + /*3144*/ uint16(xArgXmm1), + /*3145*/ uint16(xArgXmm2M128), + /*3146*/ uint16(xArgImm8u), + /*3147*/ uint16(xMatch), + /*3148*/ uint16(xCondPrefix), 1, + 0x66, 3152, + /*3152*/ uint16(xSetOp), uint16(ROUNDSS), + /*3154*/ uint16(xReadSlashR), + /*3155*/ uint16(xReadIb), + /*3156*/ uint16(xArgXmm1), + /*3157*/ uint16(xArgXmm2M32), + /*3158*/ uint16(xArgImm8u), + /*3159*/ uint16(xMatch), + /*3160*/ uint16(xCondPrefix), 1, + 0x66, 3164, + /*3164*/ uint16(xSetOp), uint16(ROUNDSD), + /*3166*/ uint16(xReadSlashR), + /*3167*/ uint16(xReadIb), + /*3168*/ uint16(xArgXmm1), + /*3169*/ uint16(xArgXmm2M64), + /*3170*/ uint16(xArgImm8u), + /*3171*/ uint16(xMatch), + /*3172*/ uint16(xCondPrefix), 1, + 0x66, 3176, + /*3176*/ uint16(xSetOp), uint16(BLENDPS), + /*3178*/ uint16(xReadSlashR), + /*3179*/ uint16(xReadIb), + /*3180*/ uint16(xArgXmm1), + /*3181*/ uint16(xArgXmm2M128), + /*3182*/ uint16(xArgImm8u), + /*3183*/ uint16(xMatch), + /*3184*/ uint16(xCondPrefix), 1, + 0x66, 3188, + /*3188*/ uint16(xSetOp), uint16(BLENDPD), + /*3190*/ uint16(xReadSlashR), + /*3191*/ uint16(xReadIb), + /*3192*/ uint16(xArgXmm1), + /*3193*/ uint16(xArgXmm2M128), + /*3194*/ uint16(xArgImm8u), + /*3195*/ uint16(xMatch), + /*3196*/ uint16(xCondPrefix), 1, + 0x66, 3200, + /*3200*/ uint16(xSetOp), uint16(PBLENDW), + /*3202*/ uint16(xReadSlashR), + /*3203*/ uint16(xReadIb), + /*3204*/ uint16(xArgXmm1), + /*3205*/ uint16(xArgXmm2M128), + /*3206*/ uint16(xArgImm8u), + /*3207*/ uint16(xMatch), + /*3208*/ uint16(xCondPrefix), 2, + 0x66, 3222, + 0x0, 3214, + /*3214*/ uint16(xSetOp), uint16(PALIGNR), + /*3216*/ uint16(xReadSlashR), + /*3217*/ uint16(xReadIb), + /*3218*/ uint16(xArgMm1), + /*3219*/ uint16(xArgMm2M64), + /*3220*/ uint16(xArgImm8u), + /*3221*/ uint16(xMatch), + /*3222*/ uint16(xSetOp), uint16(PALIGNR), + /*3224*/ uint16(xReadSlashR), + /*3225*/ uint16(xReadIb), + /*3226*/ uint16(xArgXmm1), + /*3227*/ uint16(xArgXmm2M128), + /*3228*/ uint16(xArgImm8u), + /*3229*/ uint16(xMatch), + /*3230*/ uint16(xCondPrefix), 1, + 0x66, 3234, + /*3234*/ uint16(xSetOp), uint16(PEXTRB), + /*3236*/ uint16(xReadSlashR), + /*3237*/ uint16(xReadIb), + /*3238*/ uint16(xArgR32M8), + /*3239*/ uint16(xArgXmm1), + /*3240*/ uint16(xArgImm8u), + /*3241*/ uint16(xMatch), + /*3242*/ uint16(xCondPrefix), 1, + 0x66, 3246, + /*3246*/ uint16(xSetOp), uint16(PEXTRW), + /*3248*/ uint16(xReadSlashR), + /*3249*/ uint16(xReadIb), + /*3250*/ uint16(xArgR32M16), + /*3251*/ uint16(xArgXmm1), + /*3252*/ uint16(xArgImm8u), + /*3253*/ uint16(xMatch), + /*3254*/ uint16(xCondIs64), 3257, 3281, + /*3257*/ uint16(xCondPrefix), 1, + 0x66, 3261, + /*3261*/ uint16(xCondDataSize), 3265, 3273, 0, + /*3265*/ uint16(xSetOp), uint16(PEXTRD), + /*3267*/ uint16(xReadSlashR), + /*3268*/ uint16(xReadIb), + /*3269*/ uint16(xArgRM32), + /*3270*/ uint16(xArgXmm1), + /*3271*/ uint16(xArgImm8u), + /*3272*/ uint16(xMatch), + /*3273*/ uint16(xSetOp), uint16(PEXTRD), + /*3275*/ uint16(xReadSlashR), + /*3276*/ uint16(xReadIb), + /*3277*/ uint16(xArgRM32), + /*3278*/ uint16(xArgXmm1), + /*3279*/ uint16(xArgImm8u), + /*3280*/ uint16(xMatch), + /*3281*/ uint16(xCondPrefix), 1, + 0x66, 3285, + /*3285*/ uint16(xCondDataSize), 3265, 3273, 3289, + /*3289*/ uint16(xSetOp), uint16(PEXTRQ), + /*3291*/ uint16(xReadSlashR), + /*3292*/ uint16(xReadIb), + /*3293*/ uint16(xArgRM64), + /*3294*/ uint16(xArgXmm1), + /*3295*/ uint16(xArgImm8u), + /*3296*/ uint16(xMatch), + /*3297*/ uint16(xCondPrefix), 1, + 0x66, 3301, + /*3301*/ uint16(xSetOp), uint16(EXTRACTPS), + /*3303*/ uint16(xReadSlashR), + /*3304*/ uint16(xReadIb), + /*3305*/ uint16(xArgRM32), + /*3306*/ uint16(xArgXmm1), + /*3307*/ uint16(xArgImm8u), + /*3308*/ uint16(xMatch), + /*3309*/ uint16(xCondPrefix), 1, + 0x66, 3313, + /*3313*/ uint16(xSetOp), uint16(PINSRB), + /*3315*/ uint16(xReadSlashR), + /*3316*/ uint16(xReadIb), + /*3317*/ uint16(xArgXmm1), + /*3318*/ uint16(xArgR32M8), + /*3319*/ uint16(xArgImm8u), + /*3320*/ uint16(xMatch), + /*3321*/ uint16(xCondPrefix), 1, + 0x66, 3325, + /*3325*/ uint16(xSetOp), uint16(INSERTPS), + /*3327*/ uint16(xReadSlashR), + /*3328*/ uint16(xReadIb), + /*3329*/ uint16(xArgXmm1), + /*3330*/ uint16(xArgXmm2M32), + /*3331*/ uint16(xArgImm8u), + /*3332*/ uint16(xMatch), + /*3333*/ uint16(xCondIs64), 3336, 3360, + /*3336*/ uint16(xCondPrefix), 1, + 0x66, 3340, + /*3340*/ uint16(xCondDataSize), 3344, 3352, 0, + /*3344*/ uint16(xSetOp), uint16(PINSRD), + /*3346*/ uint16(xReadSlashR), + /*3347*/ uint16(xReadIb), + /*3348*/ uint16(xArgXmm1), + /*3349*/ uint16(xArgRM32), + /*3350*/ uint16(xArgImm8u), + /*3351*/ uint16(xMatch), + /*3352*/ uint16(xSetOp), uint16(PINSRD), + /*3354*/ uint16(xReadSlashR), + /*3355*/ uint16(xReadIb), + /*3356*/ uint16(xArgXmm1), + /*3357*/ uint16(xArgRM32), + /*3358*/ uint16(xArgImm8u), + /*3359*/ uint16(xMatch), + /*3360*/ uint16(xCondPrefix), 1, + 0x66, 3364, + /*3364*/ uint16(xCondDataSize), 3344, 3352, 3368, + /*3368*/ uint16(xSetOp), uint16(PINSRQ), + /*3370*/ uint16(xReadSlashR), + /*3371*/ uint16(xReadIb), + /*3372*/ uint16(xArgXmm1), + /*3373*/ uint16(xArgRM64), + /*3374*/ uint16(xArgImm8u), + /*3375*/ uint16(xMatch), + /*3376*/ uint16(xCondPrefix), 1, + 0x66, 3380, + /*3380*/ uint16(xSetOp), uint16(DPPS), + /*3382*/ uint16(xReadSlashR), + /*3383*/ uint16(xReadIb), + /*3384*/ uint16(xArgXmm1), + /*3385*/ uint16(xArgXmm2M128), + /*3386*/ uint16(xArgImm8u), + /*3387*/ uint16(xMatch), + /*3388*/ uint16(xCondPrefix), 1, + 0x66, 3392, + /*3392*/ uint16(xSetOp), uint16(DPPD), + /*3394*/ uint16(xReadSlashR), + /*3395*/ uint16(xReadIb), + /*3396*/ uint16(xArgXmm1), + /*3397*/ uint16(xArgXmm2M128), + /*3398*/ uint16(xArgImm8u), + /*3399*/ uint16(xMatch), + /*3400*/ uint16(xCondPrefix), 1, + 0x66, 3404, + /*3404*/ uint16(xSetOp), uint16(MPSADBW), + /*3406*/ uint16(xReadSlashR), + /*3407*/ uint16(xReadIb), + /*3408*/ uint16(xArgXmm1), + /*3409*/ uint16(xArgXmm2M128), + /*3410*/ uint16(xArgImm8u), + /*3411*/ uint16(xMatch), + /*3412*/ uint16(xCondPrefix), 1, + 0x66, 3416, + /*3416*/ uint16(xSetOp), uint16(PCLMULQDQ), + /*3418*/ uint16(xReadSlashR), + /*3419*/ uint16(xReadIb), + /*3420*/ uint16(xArgXmm1), + /*3421*/ uint16(xArgXmm2M128), + /*3422*/ uint16(xArgImm8u), + /*3423*/ uint16(xMatch), + /*3424*/ uint16(xCondPrefix), 1, + 0x66, 3428, + /*3428*/ uint16(xSetOp), uint16(PCMPESTRM), + /*3430*/ uint16(xReadSlashR), + /*3431*/ uint16(xReadIb), + /*3432*/ uint16(xArgXmm1), + /*3433*/ uint16(xArgXmm2M128), + /*3434*/ uint16(xArgImm8u), + /*3435*/ uint16(xMatch), + /*3436*/ uint16(xCondPrefix), 1, + 0x66, 3440, + /*3440*/ uint16(xSetOp), uint16(PCMPESTRI), + /*3442*/ uint16(xReadSlashR), + /*3443*/ uint16(xReadIb), + /*3444*/ uint16(xArgXmm1), + /*3445*/ uint16(xArgXmm2M128), + /*3446*/ uint16(xArgImm8u), + /*3447*/ uint16(xMatch), + /*3448*/ uint16(xCondPrefix), 1, + 0x66, 3452, + /*3452*/ uint16(xSetOp), uint16(PCMPISTRM), + /*3454*/ uint16(xReadSlashR), + /*3455*/ uint16(xReadIb), + /*3456*/ uint16(xArgXmm1), + /*3457*/ uint16(xArgXmm2M128), + /*3458*/ uint16(xArgImm8u), + /*3459*/ uint16(xMatch), + /*3460*/ uint16(xCondPrefix), 1, + 0x66, 3464, + /*3464*/ uint16(xSetOp), uint16(PCMPISTRI), + /*3466*/ uint16(xReadSlashR), + /*3467*/ uint16(xReadIb), + /*3468*/ uint16(xArgXmm1), + /*3469*/ uint16(xArgXmm2M128), + /*3470*/ uint16(xArgImm8u), + /*3471*/ uint16(xMatch), + /*3472*/ uint16(xCondPrefix), 1, + 0x66, 3476, + /*3476*/ uint16(xSetOp), uint16(AESKEYGENASSIST), + /*3478*/ uint16(xReadSlashR), + /*3479*/ uint16(xReadIb), + /*3480*/ uint16(xArgXmm1), + /*3481*/ uint16(xArgXmm2M128), + /*3482*/ uint16(xArgImm8u), + /*3483*/ uint16(xMatch), + /*3484*/ uint16(xCondIs64), 3487, 3503, + /*3487*/ uint16(xCondDataSize), 3491, 3497, 0, + /*3491*/ uint16(xSetOp), uint16(CMOVO), + /*3493*/ uint16(xReadSlashR), + /*3494*/ uint16(xArgR16), + /*3495*/ uint16(xArgRM16), + /*3496*/ uint16(xMatch), + /*3497*/ uint16(xSetOp), uint16(CMOVO), + /*3499*/ uint16(xReadSlashR), + /*3500*/ uint16(xArgR32), + /*3501*/ uint16(xArgRM32), + /*3502*/ uint16(xMatch), + /*3503*/ uint16(xCondDataSize), 3491, 3497, 3507, + /*3507*/ uint16(xSetOp), uint16(CMOVO), + /*3509*/ uint16(xReadSlashR), + /*3510*/ uint16(xArgR64), + /*3511*/ uint16(xArgRM64), + /*3512*/ uint16(xMatch), + /*3513*/ uint16(xCondIs64), 3516, 3532, + /*3516*/ uint16(xCondDataSize), 3520, 3526, 0, + /*3520*/ uint16(xSetOp), uint16(CMOVNO), + /*3522*/ uint16(xReadSlashR), + /*3523*/ uint16(xArgR16), + /*3524*/ uint16(xArgRM16), + /*3525*/ uint16(xMatch), + /*3526*/ uint16(xSetOp), uint16(CMOVNO), + /*3528*/ uint16(xReadSlashR), + /*3529*/ uint16(xArgR32), + /*3530*/ uint16(xArgRM32), + /*3531*/ uint16(xMatch), + /*3532*/ uint16(xCondDataSize), 3520, 3526, 3536, + /*3536*/ uint16(xSetOp), uint16(CMOVNO), + /*3538*/ uint16(xReadSlashR), + /*3539*/ uint16(xArgR64), + /*3540*/ uint16(xArgRM64), + /*3541*/ uint16(xMatch), + /*3542*/ uint16(xCondIs64), 3545, 3561, + /*3545*/ uint16(xCondDataSize), 3549, 3555, 0, + /*3549*/ uint16(xSetOp), uint16(CMOVB), + /*3551*/ uint16(xReadSlashR), + /*3552*/ uint16(xArgR16), + /*3553*/ uint16(xArgRM16), + /*3554*/ uint16(xMatch), + /*3555*/ uint16(xSetOp), uint16(CMOVB), + /*3557*/ uint16(xReadSlashR), + /*3558*/ uint16(xArgR32), + /*3559*/ uint16(xArgRM32), + /*3560*/ uint16(xMatch), + /*3561*/ uint16(xCondDataSize), 3549, 3555, 3565, + /*3565*/ uint16(xSetOp), uint16(CMOVB), + /*3567*/ uint16(xReadSlashR), + /*3568*/ uint16(xArgR64), + /*3569*/ uint16(xArgRM64), + /*3570*/ uint16(xMatch), + /*3571*/ uint16(xCondIs64), 3574, 3590, + /*3574*/ uint16(xCondDataSize), 3578, 3584, 0, + /*3578*/ uint16(xSetOp), uint16(CMOVAE), + /*3580*/ uint16(xReadSlashR), + /*3581*/ uint16(xArgR16), + /*3582*/ uint16(xArgRM16), + /*3583*/ uint16(xMatch), + /*3584*/ uint16(xSetOp), uint16(CMOVAE), + /*3586*/ uint16(xReadSlashR), + /*3587*/ uint16(xArgR32), + /*3588*/ uint16(xArgRM32), + /*3589*/ uint16(xMatch), + /*3590*/ uint16(xCondDataSize), 3578, 3584, 3594, + /*3594*/ uint16(xSetOp), uint16(CMOVAE), + /*3596*/ uint16(xReadSlashR), + /*3597*/ uint16(xArgR64), + /*3598*/ uint16(xArgRM64), + /*3599*/ uint16(xMatch), + /*3600*/ uint16(xCondIs64), 3603, 3619, + /*3603*/ uint16(xCondDataSize), 3607, 3613, 0, + /*3607*/ uint16(xSetOp), uint16(CMOVE), + /*3609*/ uint16(xReadSlashR), + /*3610*/ uint16(xArgR16), + /*3611*/ uint16(xArgRM16), + /*3612*/ uint16(xMatch), + /*3613*/ uint16(xSetOp), uint16(CMOVE), + /*3615*/ uint16(xReadSlashR), + /*3616*/ uint16(xArgR32), + /*3617*/ uint16(xArgRM32), + /*3618*/ uint16(xMatch), + /*3619*/ uint16(xCondDataSize), 3607, 3613, 3623, + /*3623*/ uint16(xSetOp), uint16(CMOVE), + /*3625*/ uint16(xReadSlashR), + /*3626*/ uint16(xArgR64), + /*3627*/ uint16(xArgRM64), + /*3628*/ uint16(xMatch), + /*3629*/ uint16(xCondIs64), 3632, 3648, + /*3632*/ uint16(xCondDataSize), 3636, 3642, 0, + /*3636*/ uint16(xSetOp), uint16(CMOVNE), + /*3638*/ uint16(xReadSlashR), + /*3639*/ uint16(xArgR16), + /*3640*/ uint16(xArgRM16), + /*3641*/ uint16(xMatch), + /*3642*/ uint16(xSetOp), uint16(CMOVNE), + /*3644*/ uint16(xReadSlashR), + /*3645*/ uint16(xArgR32), + /*3646*/ uint16(xArgRM32), + /*3647*/ uint16(xMatch), + /*3648*/ uint16(xCondDataSize), 3636, 3642, 3652, + /*3652*/ uint16(xSetOp), uint16(CMOVNE), + /*3654*/ uint16(xReadSlashR), + /*3655*/ uint16(xArgR64), + /*3656*/ uint16(xArgRM64), + /*3657*/ uint16(xMatch), + /*3658*/ uint16(xCondIs64), 3661, 3677, + /*3661*/ uint16(xCondDataSize), 3665, 3671, 0, + /*3665*/ uint16(xSetOp), uint16(CMOVBE), + /*3667*/ uint16(xReadSlashR), + /*3668*/ uint16(xArgR16), + /*3669*/ uint16(xArgRM16), + /*3670*/ uint16(xMatch), + /*3671*/ uint16(xSetOp), uint16(CMOVBE), + /*3673*/ uint16(xReadSlashR), + /*3674*/ uint16(xArgR32), + /*3675*/ uint16(xArgRM32), + /*3676*/ uint16(xMatch), + /*3677*/ uint16(xCondDataSize), 3665, 3671, 3681, + /*3681*/ uint16(xSetOp), uint16(CMOVBE), + /*3683*/ uint16(xReadSlashR), + /*3684*/ uint16(xArgR64), + /*3685*/ uint16(xArgRM64), + /*3686*/ uint16(xMatch), + /*3687*/ uint16(xCondIs64), 3690, 3706, + /*3690*/ uint16(xCondDataSize), 3694, 3700, 0, + /*3694*/ uint16(xSetOp), uint16(CMOVA), + /*3696*/ uint16(xReadSlashR), + /*3697*/ uint16(xArgR16), + /*3698*/ uint16(xArgRM16), + /*3699*/ uint16(xMatch), + /*3700*/ uint16(xSetOp), uint16(CMOVA), + /*3702*/ uint16(xReadSlashR), + /*3703*/ uint16(xArgR32), + /*3704*/ uint16(xArgRM32), + /*3705*/ uint16(xMatch), + /*3706*/ uint16(xCondDataSize), 3694, 3700, 3710, + /*3710*/ uint16(xSetOp), uint16(CMOVA), + /*3712*/ uint16(xReadSlashR), + /*3713*/ uint16(xArgR64), + /*3714*/ uint16(xArgRM64), + /*3715*/ uint16(xMatch), + /*3716*/ uint16(xCondIs64), 3719, 3735, + /*3719*/ uint16(xCondDataSize), 3723, 3729, 0, + /*3723*/ uint16(xSetOp), uint16(CMOVS), + /*3725*/ uint16(xReadSlashR), + /*3726*/ uint16(xArgR16), + /*3727*/ uint16(xArgRM16), + /*3728*/ uint16(xMatch), + /*3729*/ uint16(xSetOp), uint16(CMOVS), + /*3731*/ uint16(xReadSlashR), + /*3732*/ uint16(xArgR32), + /*3733*/ uint16(xArgRM32), + /*3734*/ uint16(xMatch), + /*3735*/ uint16(xCondDataSize), 3723, 3729, 3739, + /*3739*/ uint16(xSetOp), uint16(CMOVS), + /*3741*/ uint16(xReadSlashR), + /*3742*/ uint16(xArgR64), + /*3743*/ uint16(xArgRM64), + /*3744*/ uint16(xMatch), + /*3745*/ uint16(xCondIs64), 3748, 3764, + /*3748*/ uint16(xCondDataSize), 3752, 3758, 0, + /*3752*/ uint16(xSetOp), uint16(CMOVNS), + /*3754*/ uint16(xReadSlashR), + /*3755*/ uint16(xArgR16), + /*3756*/ uint16(xArgRM16), + /*3757*/ uint16(xMatch), + /*3758*/ uint16(xSetOp), uint16(CMOVNS), + /*3760*/ uint16(xReadSlashR), + /*3761*/ uint16(xArgR32), + /*3762*/ uint16(xArgRM32), + /*3763*/ uint16(xMatch), + /*3764*/ uint16(xCondDataSize), 3752, 3758, 3768, + /*3768*/ uint16(xSetOp), uint16(CMOVNS), + /*3770*/ uint16(xReadSlashR), + /*3771*/ uint16(xArgR64), + /*3772*/ uint16(xArgRM64), + /*3773*/ uint16(xMatch), + /*3774*/ uint16(xCondIs64), 3777, 3793, + /*3777*/ uint16(xCondDataSize), 3781, 3787, 0, + /*3781*/ uint16(xSetOp), uint16(CMOVP), + /*3783*/ uint16(xReadSlashR), + /*3784*/ uint16(xArgR16), + /*3785*/ uint16(xArgRM16), + /*3786*/ uint16(xMatch), + /*3787*/ uint16(xSetOp), uint16(CMOVP), + /*3789*/ uint16(xReadSlashR), + /*3790*/ uint16(xArgR32), + /*3791*/ uint16(xArgRM32), + /*3792*/ uint16(xMatch), + /*3793*/ uint16(xCondDataSize), 3781, 3787, 3797, + /*3797*/ uint16(xSetOp), uint16(CMOVP), + /*3799*/ uint16(xReadSlashR), + /*3800*/ uint16(xArgR64), + /*3801*/ uint16(xArgRM64), + /*3802*/ uint16(xMatch), + /*3803*/ uint16(xCondIs64), 3806, 3822, + /*3806*/ uint16(xCondDataSize), 3810, 3816, 0, + /*3810*/ uint16(xSetOp), uint16(CMOVNP), + /*3812*/ uint16(xReadSlashR), + /*3813*/ uint16(xArgR16), + /*3814*/ uint16(xArgRM16), + /*3815*/ uint16(xMatch), + /*3816*/ uint16(xSetOp), uint16(CMOVNP), + /*3818*/ uint16(xReadSlashR), + /*3819*/ uint16(xArgR32), + /*3820*/ uint16(xArgRM32), + /*3821*/ uint16(xMatch), + /*3822*/ uint16(xCondDataSize), 3810, 3816, 3826, + /*3826*/ uint16(xSetOp), uint16(CMOVNP), + /*3828*/ uint16(xReadSlashR), + /*3829*/ uint16(xArgR64), + /*3830*/ uint16(xArgRM64), + /*3831*/ uint16(xMatch), + /*3832*/ uint16(xCondIs64), 3835, 3851, + /*3835*/ uint16(xCondDataSize), 3839, 3845, 0, + /*3839*/ uint16(xSetOp), uint16(CMOVL), + /*3841*/ uint16(xReadSlashR), + /*3842*/ uint16(xArgR16), + /*3843*/ uint16(xArgRM16), + /*3844*/ uint16(xMatch), + /*3845*/ uint16(xSetOp), uint16(CMOVL), + /*3847*/ uint16(xReadSlashR), + /*3848*/ uint16(xArgR32), + /*3849*/ uint16(xArgRM32), + /*3850*/ uint16(xMatch), + /*3851*/ uint16(xCondDataSize), 3839, 3845, 3855, + /*3855*/ uint16(xSetOp), uint16(CMOVL), + /*3857*/ uint16(xReadSlashR), + /*3858*/ uint16(xArgR64), + /*3859*/ uint16(xArgRM64), + /*3860*/ uint16(xMatch), + /*3861*/ uint16(xCondIs64), 3864, 3880, + /*3864*/ uint16(xCondDataSize), 3868, 3874, 0, + /*3868*/ uint16(xSetOp), uint16(CMOVGE), + /*3870*/ uint16(xReadSlashR), + /*3871*/ uint16(xArgR16), + /*3872*/ uint16(xArgRM16), + /*3873*/ uint16(xMatch), + /*3874*/ uint16(xSetOp), uint16(CMOVGE), + /*3876*/ uint16(xReadSlashR), + /*3877*/ uint16(xArgR32), + /*3878*/ uint16(xArgRM32), + /*3879*/ uint16(xMatch), + /*3880*/ uint16(xCondDataSize), 3868, 3874, 3884, + /*3884*/ uint16(xSetOp), uint16(CMOVGE), + /*3886*/ uint16(xReadSlashR), + /*3887*/ uint16(xArgR64), + /*3888*/ uint16(xArgRM64), + /*3889*/ uint16(xMatch), + /*3890*/ uint16(xCondIs64), 3893, 3909, + /*3893*/ uint16(xCondDataSize), 3897, 3903, 0, + /*3897*/ uint16(xSetOp), uint16(CMOVLE), + /*3899*/ uint16(xReadSlashR), + /*3900*/ uint16(xArgR16), + /*3901*/ uint16(xArgRM16), + /*3902*/ uint16(xMatch), + /*3903*/ uint16(xSetOp), uint16(CMOVLE), + /*3905*/ uint16(xReadSlashR), + /*3906*/ uint16(xArgR32), + /*3907*/ uint16(xArgRM32), + /*3908*/ uint16(xMatch), + /*3909*/ uint16(xCondDataSize), 3897, 3903, 3913, + /*3913*/ uint16(xSetOp), uint16(CMOVLE), + /*3915*/ uint16(xReadSlashR), + /*3916*/ uint16(xArgR64), + /*3917*/ uint16(xArgRM64), + /*3918*/ uint16(xMatch), + /*3919*/ uint16(xCondIs64), 3922, 3938, + /*3922*/ uint16(xCondDataSize), 3926, 3932, 0, + /*3926*/ uint16(xSetOp), uint16(CMOVG), + /*3928*/ uint16(xReadSlashR), + /*3929*/ uint16(xArgR16), + /*3930*/ uint16(xArgRM16), + /*3931*/ uint16(xMatch), + /*3932*/ uint16(xSetOp), uint16(CMOVG), + /*3934*/ uint16(xReadSlashR), + /*3935*/ uint16(xArgR32), + /*3936*/ uint16(xArgRM32), + /*3937*/ uint16(xMatch), + /*3938*/ uint16(xCondDataSize), 3926, 3932, 3942, + /*3942*/ uint16(xSetOp), uint16(CMOVG), + /*3944*/ uint16(xReadSlashR), + /*3945*/ uint16(xArgR64), + /*3946*/ uint16(xArgRM64), + /*3947*/ uint16(xMatch), + /*3948*/ uint16(xCondPrefix), 2, + 0x66, 3960, + 0x0, 3954, + /*3954*/ uint16(xSetOp), uint16(MOVMSKPS), + /*3956*/ uint16(xReadSlashR), + /*3957*/ uint16(xArgR32), + /*3958*/ uint16(xArgXmm2), + /*3959*/ uint16(xMatch), + /*3960*/ uint16(xSetOp), uint16(MOVMSKPD), + /*3962*/ uint16(xReadSlashR), + /*3963*/ uint16(xArgR32), + /*3964*/ uint16(xArgXmm2), + /*3965*/ uint16(xMatch), + /*3966*/ uint16(xCondPrefix), 4, + 0xF3, 3994, + 0xF2, 3988, + 0x66, 3982, + 0x0, 3976, + /*3976*/ uint16(xSetOp), uint16(SQRTPS), + /*3978*/ uint16(xReadSlashR), + /*3979*/ uint16(xArgXmm1), + /*3980*/ uint16(xArgXmm2M128), + /*3981*/ uint16(xMatch), + /*3982*/ uint16(xSetOp), uint16(SQRTPD), + /*3984*/ uint16(xReadSlashR), + /*3985*/ uint16(xArgXmm1), + /*3986*/ uint16(xArgXmm2M128), + /*3987*/ uint16(xMatch), + /*3988*/ uint16(xSetOp), uint16(SQRTSD), + /*3990*/ uint16(xReadSlashR), + /*3991*/ uint16(xArgXmm1), + /*3992*/ uint16(xArgXmm2M64), + /*3993*/ uint16(xMatch), + /*3994*/ uint16(xSetOp), uint16(SQRTSS), + /*3996*/ uint16(xReadSlashR), + /*3997*/ uint16(xArgXmm1), + /*3998*/ uint16(xArgXmm2M32), + /*3999*/ uint16(xMatch), + /*4000*/ uint16(xCondPrefix), 2, + 0xF3, 4012, + 0x0, 4006, + /*4006*/ uint16(xSetOp), uint16(RSQRTPS), + /*4008*/ uint16(xReadSlashR), + /*4009*/ uint16(xArgXmm1), + /*4010*/ uint16(xArgXmm2M128), + /*4011*/ uint16(xMatch), + /*4012*/ uint16(xSetOp), uint16(RSQRTSS), + /*4014*/ uint16(xReadSlashR), + /*4015*/ uint16(xArgXmm1), + /*4016*/ uint16(xArgXmm2M32), + /*4017*/ uint16(xMatch), + /*4018*/ uint16(xCondPrefix), 2, + 0xF3, 4030, + 0x0, 4024, + /*4024*/ uint16(xSetOp), uint16(RCPPS), + /*4026*/ uint16(xReadSlashR), + /*4027*/ uint16(xArgXmm1), + /*4028*/ uint16(xArgXmm2M128), + /*4029*/ uint16(xMatch), + /*4030*/ uint16(xSetOp), uint16(RCPSS), + /*4032*/ uint16(xReadSlashR), + /*4033*/ uint16(xArgXmm1), + /*4034*/ uint16(xArgXmm2M32), + /*4035*/ uint16(xMatch), + /*4036*/ uint16(xCondPrefix), 2, + 0x66, 4048, + 0x0, 4042, + /*4042*/ uint16(xSetOp), uint16(ANDPS), + /*4044*/ uint16(xReadSlashR), + /*4045*/ uint16(xArgXmm1), + /*4046*/ uint16(xArgXmm2M128), + /*4047*/ uint16(xMatch), + /*4048*/ uint16(xSetOp), uint16(ANDPD), + /*4050*/ uint16(xReadSlashR), + /*4051*/ uint16(xArgXmm1), + /*4052*/ uint16(xArgXmm2M128), + /*4053*/ uint16(xMatch), + /*4054*/ uint16(xCondPrefix), 2, + 0x66, 4066, + 0x0, 4060, + /*4060*/ uint16(xSetOp), uint16(ANDNPS), + /*4062*/ uint16(xReadSlashR), + /*4063*/ uint16(xArgXmm1), + /*4064*/ uint16(xArgXmm2M128), + /*4065*/ uint16(xMatch), + /*4066*/ uint16(xSetOp), uint16(ANDNPD), + /*4068*/ uint16(xReadSlashR), + /*4069*/ uint16(xArgXmm1), + /*4070*/ uint16(xArgXmm2M128), + /*4071*/ uint16(xMatch), + /*4072*/ uint16(xCondPrefix), 2, + 0x66, 4084, + 0x0, 4078, + /*4078*/ uint16(xSetOp), uint16(ORPS), + /*4080*/ uint16(xReadSlashR), + /*4081*/ uint16(xArgXmm1), + /*4082*/ uint16(xArgXmm2M128), + /*4083*/ uint16(xMatch), + /*4084*/ uint16(xSetOp), uint16(ORPD), + /*4086*/ uint16(xReadSlashR), + /*4087*/ uint16(xArgXmm1), + /*4088*/ uint16(xArgXmm2M128), + /*4089*/ uint16(xMatch), + /*4090*/ uint16(xCondPrefix), 2, + 0x66, 4102, + 0x0, 4096, + /*4096*/ uint16(xSetOp), uint16(XORPS), + /*4098*/ uint16(xReadSlashR), + /*4099*/ uint16(xArgXmm1), + /*4100*/ uint16(xArgXmm2M128), + /*4101*/ uint16(xMatch), + /*4102*/ uint16(xSetOp), uint16(XORPD), + /*4104*/ uint16(xReadSlashR), + /*4105*/ uint16(xArgXmm1), + /*4106*/ uint16(xArgXmm2M128), + /*4107*/ uint16(xMatch), + /*4108*/ uint16(xCondPrefix), 4, + 0xF3, 4136, + 0xF2, 4130, + 0x66, 4124, + 0x0, 4118, + /*4118*/ uint16(xSetOp), uint16(ADDPS), + /*4120*/ uint16(xReadSlashR), + /*4121*/ uint16(xArgXmm1), + /*4122*/ uint16(xArgXmm2M128), + /*4123*/ uint16(xMatch), + /*4124*/ uint16(xSetOp), uint16(ADDPD), + /*4126*/ uint16(xReadSlashR), + /*4127*/ uint16(xArgXmm1), + /*4128*/ uint16(xArgXmm2M128), + /*4129*/ uint16(xMatch), + /*4130*/ uint16(xSetOp), uint16(ADDSD), + /*4132*/ uint16(xReadSlashR), + /*4133*/ uint16(xArgXmm1), + /*4134*/ uint16(xArgXmm2M64), + /*4135*/ uint16(xMatch), + /*4136*/ uint16(xSetOp), uint16(ADDSS), + /*4138*/ uint16(xReadSlashR), + /*4139*/ uint16(xArgXmm1), + /*4140*/ uint16(xArgXmm2M32), + /*4141*/ uint16(xMatch), + /*4142*/ uint16(xCondPrefix), 4, + 0xF3, 4170, + 0xF2, 4164, + 0x66, 4158, + 0x0, 4152, + /*4152*/ uint16(xSetOp), uint16(MULPS), + /*4154*/ uint16(xReadSlashR), + /*4155*/ uint16(xArgXmm1), + /*4156*/ uint16(xArgXmm2M128), + /*4157*/ uint16(xMatch), + /*4158*/ uint16(xSetOp), uint16(MULPD), + /*4160*/ uint16(xReadSlashR), + /*4161*/ uint16(xArgXmm1), + /*4162*/ uint16(xArgXmm2M128), + /*4163*/ uint16(xMatch), + /*4164*/ uint16(xSetOp), uint16(MULSD), + /*4166*/ uint16(xReadSlashR), + /*4167*/ uint16(xArgXmm1), + /*4168*/ uint16(xArgXmm2M64), + /*4169*/ uint16(xMatch), + /*4170*/ uint16(xSetOp), uint16(MULSS), + /*4172*/ uint16(xReadSlashR), + /*4173*/ uint16(xArgXmm1), + /*4174*/ uint16(xArgXmm2M32), + /*4175*/ uint16(xMatch), + /*4176*/ uint16(xCondPrefix), 4, + 0xF3, 4204, + 0xF2, 4198, + 0x66, 4192, + 0x0, 4186, + /*4186*/ uint16(xSetOp), uint16(CVTPS2PD), + /*4188*/ uint16(xReadSlashR), + /*4189*/ uint16(xArgXmm1), + /*4190*/ uint16(xArgXmm2M64), + /*4191*/ uint16(xMatch), + /*4192*/ uint16(xSetOp), uint16(CVTPD2PS), + /*4194*/ uint16(xReadSlashR), + /*4195*/ uint16(xArgXmm1), + /*4196*/ uint16(xArgXmm2M128), + /*4197*/ uint16(xMatch), + /*4198*/ uint16(xSetOp), uint16(CVTSD2SS), + /*4200*/ uint16(xReadSlashR), + /*4201*/ uint16(xArgXmm1), + /*4202*/ uint16(xArgXmm2M64), + /*4203*/ uint16(xMatch), + /*4204*/ uint16(xSetOp), uint16(CVTSS2SD), + /*4206*/ uint16(xReadSlashR), + /*4207*/ uint16(xArgXmm1), + /*4208*/ uint16(xArgXmm2M32), + /*4209*/ uint16(xMatch), + /*4210*/ uint16(xCondPrefix), 3, + 0xF3, 4230, + 0x66, 4224, + 0x0, 4218, + /*4218*/ uint16(xSetOp), uint16(CVTDQ2PS), + /*4220*/ uint16(xReadSlashR), + /*4221*/ uint16(xArgXmm1), + /*4222*/ uint16(xArgXmm2M128), + /*4223*/ uint16(xMatch), + /*4224*/ uint16(xSetOp), uint16(CVTPS2DQ), + /*4226*/ uint16(xReadSlashR), + /*4227*/ uint16(xArgXmm1), + /*4228*/ uint16(xArgXmm2M128), + /*4229*/ uint16(xMatch), + /*4230*/ uint16(xSetOp), uint16(CVTTPS2DQ), + /*4232*/ uint16(xReadSlashR), + /*4233*/ uint16(xArgXmm1), + /*4234*/ uint16(xArgXmm2M128), + /*4235*/ uint16(xMatch), + /*4236*/ uint16(xCondPrefix), 4, + 0xF3, 4264, + 0xF2, 4258, + 0x66, 4252, + 0x0, 4246, + /*4246*/ uint16(xSetOp), uint16(SUBPS), + /*4248*/ uint16(xReadSlashR), + /*4249*/ uint16(xArgXmm1), + /*4250*/ uint16(xArgXmm2M128), + /*4251*/ uint16(xMatch), + /*4252*/ uint16(xSetOp), uint16(SUBPD), + /*4254*/ uint16(xReadSlashR), + /*4255*/ uint16(xArgXmm1), + /*4256*/ uint16(xArgXmm2M128), + /*4257*/ uint16(xMatch), + /*4258*/ uint16(xSetOp), uint16(SUBSD), + /*4260*/ uint16(xReadSlashR), + /*4261*/ uint16(xArgXmm1), + /*4262*/ uint16(xArgXmm2M64), + /*4263*/ uint16(xMatch), + /*4264*/ uint16(xSetOp), uint16(SUBSS), + /*4266*/ uint16(xReadSlashR), + /*4267*/ uint16(xArgXmm1), + /*4268*/ uint16(xArgXmm2M32), + /*4269*/ uint16(xMatch), + /*4270*/ uint16(xCondPrefix), 4, + 0xF3, 4298, + 0xF2, 4292, + 0x66, 4286, + 0x0, 4280, + /*4280*/ uint16(xSetOp), uint16(MINPS), + /*4282*/ uint16(xReadSlashR), + /*4283*/ uint16(xArgXmm1), + /*4284*/ uint16(xArgXmm2M128), + /*4285*/ uint16(xMatch), + /*4286*/ uint16(xSetOp), uint16(MINPD), + /*4288*/ uint16(xReadSlashR), + /*4289*/ uint16(xArgXmm1), + /*4290*/ uint16(xArgXmm2M128), + /*4291*/ uint16(xMatch), + /*4292*/ uint16(xSetOp), uint16(MINSD), + /*4294*/ uint16(xReadSlashR), + /*4295*/ uint16(xArgXmm1), + /*4296*/ uint16(xArgXmm2M64), + /*4297*/ uint16(xMatch), + /*4298*/ uint16(xSetOp), uint16(MINSS), + /*4300*/ uint16(xReadSlashR), + /*4301*/ uint16(xArgXmm1), + /*4302*/ uint16(xArgXmm2M32), + /*4303*/ uint16(xMatch), + /*4304*/ uint16(xCondPrefix), 4, + 0xF3, 4332, + 0xF2, 4326, + 0x66, 4320, + 0x0, 4314, + /*4314*/ uint16(xSetOp), uint16(DIVPS), + /*4316*/ uint16(xReadSlashR), + /*4317*/ uint16(xArgXmm1), + /*4318*/ uint16(xArgXmm2M128), + /*4319*/ uint16(xMatch), + /*4320*/ uint16(xSetOp), uint16(DIVPD), + /*4322*/ uint16(xReadSlashR), + /*4323*/ uint16(xArgXmm1), + /*4324*/ uint16(xArgXmm2M128), + /*4325*/ uint16(xMatch), + /*4326*/ uint16(xSetOp), uint16(DIVSD), + /*4328*/ uint16(xReadSlashR), + /*4329*/ uint16(xArgXmm1), + /*4330*/ uint16(xArgXmm2M64), + /*4331*/ uint16(xMatch), + /*4332*/ uint16(xSetOp), uint16(DIVSS), + /*4334*/ uint16(xReadSlashR), + /*4335*/ uint16(xArgXmm1), + /*4336*/ uint16(xArgXmm2M32), + /*4337*/ uint16(xMatch), + /*4338*/ uint16(xCondPrefix), 4, + 0xF3, 4366, + 0xF2, 4360, + 0x66, 4354, + 0x0, 4348, + /*4348*/ uint16(xSetOp), uint16(MAXPS), + /*4350*/ uint16(xReadSlashR), + /*4351*/ uint16(xArgXmm1), + /*4352*/ uint16(xArgXmm2M128), + /*4353*/ uint16(xMatch), + /*4354*/ uint16(xSetOp), uint16(MAXPD), + /*4356*/ uint16(xReadSlashR), + /*4357*/ uint16(xArgXmm1), + /*4358*/ uint16(xArgXmm2M128), + /*4359*/ uint16(xMatch), + /*4360*/ uint16(xSetOp), uint16(MAXSD), + /*4362*/ uint16(xReadSlashR), + /*4363*/ uint16(xArgXmm1), + /*4364*/ uint16(xArgXmm2M64), + /*4365*/ uint16(xMatch), + /*4366*/ uint16(xSetOp), uint16(MAXSS), + /*4368*/ uint16(xReadSlashR), + /*4369*/ uint16(xArgXmm1), + /*4370*/ uint16(xArgXmm2M32), + /*4371*/ uint16(xMatch), + /*4372*/ uint16(xCondPrefix), 2, + 0x66, 4384, + 0x0, 4378, + /*4378*/ uint16(xSetOp), uint16(PUNPCKLBW), + /*4380*/ uint16(xReadSlashR), + /*4381*/ uint16(xArgMm), + /*4382*/ uint16(xArgMmM32), + /*4383*/ uint16(xMatch), + /*4384*/ uint16(xSetOp), uint16(PUNPCKLBW), + /*4386*/ uint16(xReadSlashR), + /*4387*/ uint16(xArgXmm1), + /*4388*/ uint16(xArgXmm2M128), + /*4389*/ uint16(xMatch), + /*4390*/ uint16(xCondPrefix), 2, + 0x66, 4402, + 0x0, 4396, + /*4396*/ uint16(xSetOp), uint16(PUNPCKLWD), + /*4398*/ uint16(xReadSlashR), + /*4399*/ uint16(xArgMm), + /*4400*/ uint16(xArgMmM32), + /*4401*/ uint16(xMatch), + /*4402*/ uint16(xSetOp), uint16(PUNPCKLWD), + /*4404*/ uint16(xReadSlashR), + /*4405*/ uint16(xArgXmm1), + /*4406*/ uint16(xArgXmm2M128), + /*4407*/ uint16(xMatch), + /*4408*/ uint16(xCondPrefix), 2, + 0x66, 4420, + 0x0, 4414, + /*4414*/ uint16(xSetOp), uint16(PUNPCKLDQ), + /*4416*/ uint16(xReadSlashR), + /*4417*/ uint16(xArgMm), + /*4418*/ uint16(xArgMmM32), + /*4419*/ uint16(xMatch), + /*4420*/ uint16(xSetOp), uint16(PUNPCKLDQ), + /*4422*/ uint16(xReadSlashR), + /*4423*/ uint16(xArgXmm1), + /*4424*/ uint16(xArgXmm2M128), + /*4425*/ uint16(xMatch), + /*4426*/ uint16(xCondPrefix), 2, + 0x66, 4438, + 0x0, 4432, + /*4432*/ uint16(xSetOp), uint16(PACKSSWB), + /*4434*/ uint16(xReadSlashR), + /*4435*/ uint16(xArgMm1), + /*4436*/ uint16(xArgMm2M64), + /*4437*/ uint16(xMatch), + /*4438*/ uint16(xSetOp), uint16(PACKSSWB), + /*4440*/ uint16(xReadSlashR), + /*4441*/ uint16(xArgXmm1), + /*4442*/ uint16(xArgXmm2M128), + /*4443*/ uint16(xMatch), + /*4444*/ uint16(xCondPrefix), 2, + 0x66, 4456, + 0x0, 4450, + /*4450*/ uint16(xSetOp), uint16(PCMPGTB), + /*4452*/ uint16(xReadSlashR), + /*4453*/ uint16(xArgMm), + /*4454*/ uint16(xArgMmM64), + /*4455*/ uint16(xMatch), + /*4456*/ uint16(xSetOp), uint16(PCMPGTB), + /*4458*/ uint16(xReadSlashR), + /*4459*/ uint16(xArgXmm1), + /*4460*/ uint16(xArgXmm2M128), + /*4461*/ uint16(xMatch), + /*4462*/ uint16(xCondPrefix), 2, + 0x66, 4474, + 0x0, 4468, + /*4468*/ uint16(xSetOp), uint16(PCMPGTW), + /*4470*/ uint16(xReadSlashR), + /*4471*/ uint16(xArgMm), + /*4472*/ uint16(xArgMmM64), + /*4473*/ uint16(xMatch), + /*4474*/ uint16(xSetOp), uint16(PCMPGTW), + /*4476*/ uint16(xReadSlashR), + /*4477*/ uint16(xArgXmm1), + /*4478*/ uint16(xArgXmm2M128), + /*4479*/ uint16(xMatch), + /*4480*/ uint16(xCondPrefix), 2, + 0x66, 4492, + 0x0, 4486, + /*4486*/ uint16(xSetOp), uint16(PCMPGTD), + /*4488*/ uint16(xReadSlashR), + /*4489*/ uint16(xArgMm), + /*4490*/ uint16(xArgMmM64), + /*4491*/ uint16(xMatch), + /*4492*/ uint16(xSetOp), uint16(PCMPGTD), + /*4494*/ uint16(xReadSlashR), + /*4495*/ uint16(xArgXmm1), + /*4496*/ uint16(xArgXmm2M128), + /*4497*/ uint16(xMatch), + /*4498*/ uint16(xCondPrefix), 2, + 0x66, 4510, + 0x0, 4504, + /*4504*/ uint16(xSetOp), uint16(PACKUSWB), + /*4506*/ uint16(xReadSlashR), + /*4507*/ uint16(xArgMm), + /*4508*/ uint16(xArgMmM64), + /*4509*/ uint16(xMatch), + /*4510*/ uint16(xSetOp), uint16(PACKUSWB), + /*4512*/ uint16(xReadSlashR), + /*4513*/ uint16(xArgXmm1), + /*4514*/ uint16(xArgXmm2M128), + /*4515*/ uint16(xMatch), + /*4516*/ uint16(xCondPrefix), 2, + 0x66, 4528, + 0x0, 4522, + /*4522*/ uint16(xSetOp), uint16(PUNPCKHBW), + /*4524*/ uint16(xReadSlashR), + /*4525*/ uint16(xArgMm), + /*4526*/ uint16(xArgMmM64), + /*4527*/ uint16(xMatch), + /*4528*/ uint16(xSetOp), uint16(PUNPCKHBW), + /*4530*/ uint16(xReadSlashR), + /*4531*/ uint16(xArgXmm1), + /*4532*/ uint16(xArgXmm2M128), + /*4533*/ uint16(xMatch), + /*4534*/ uint16(xCondPrefix), 2, + 0x66, 4546, + 0x0, 4540, + /*4540*/ uint16(xSetOp), uint16(PUNPCKHWD), + /*4542*/ uint16(xReadSlashR), + /*4543*/ uint16(xArgMm), + /*4544*/ uint16(xArgMmM64), + /*4545*/ uint16(xMatch), + /*4546*/ uint16(xSetOp), uint16(PUNPCKHWD), + /*4548*/ uint16(xReadSlashR), + /*4549*/ uint16(xArgXmm1), + /*4550*/ uint16(xArgXmm2M128), + /*4551*/ uint16(xMatch), + /*4552*/ uint16(xCondPrefix), 2, + 0x66, 4564, + 0x0, 4558, + /*4558*/ uint16(xSetOp), uint16(PUNPCKHDQ), + /*4560*/ uint16(xReadSlashR), + /*4561*/ uint16(xArgMm), + /*4562*/ uint16(xArgMmM64), + /*4563*/ uint16(xMatch), + /*4564*/ uint16(xSetOp), uint16(PUNPCKHDQ), + /*4566*/ uint16(xReadSlashR), + /*4567*/ uint16(xArgXmm1), + /*4568*/ uint16(xArgXmm2M128), + /*4569*/ uint16(xMatch), + /*4570*/ uint16(xCondPrefix), 2, + 0x66, 4582, + 0x0, 4576, + /*4576*/ uint16(xSetOp), uint16(PACKSSDW), + /*4578*/ uint16(xReadSlashR), + /*4579*/ uint16(xArgMm1), + /*4580*/ uint16(xArgMm2M64), + /*4581*/ uint16(xMatch), + /*4582*/ uint16(xSetOp), uint16(PACKSSDW), + /*4584*/ uint16(xReadSlashR), + /*4585*/ uint16(xArgXmm1), + /*4586*/ uint16(xArgXmm2M128), + /*4587*/ uint16(xMatch), + /*4588*/ uint16(xCondPrefix), 1, + 0x66, 4592, + /*4592*/ uint16(xSetOp), uint16(PUNPCKLQDQ), + /*4594*/ uint16(xReadSlashR), + /*4595*/ uint16(xArgXmm1), + /*4596*/ uint16(xArgXmm2M128), + /*4597*/ uint16(xMatch), + /*4598*/ uint16(xCondPrefix), 1, + 0x66, 4602, + /*4602*/ uint16(xSetOp), uint16(PUNPCKHQDQ), + /*4604*/ uint16(xReadSlashR), + /*4605*/ uint16(xArgXmm1), + /*4606*/ uint16(xArgXmm2M128), + /*4607*/ uint16(xMatch), + /*4608*/ uint16(xCondIs64), 4611, 4649, + /*4611*/ uint16(xCondPrefix), 2, + 0x66, 4633, + 0x0, 4617, + /*4617*/ uint16(xCondDataSize), 4621, 4627, 0, + /*4621*/ uint16(xSetOp), uint16(MOVD), + /*4623*/ uint16(xReadSlashR), + /*4624*/ uint16(xArgMm), + /*4625*/ uint16(xArgRM32), + /*4626*/ uint16(xMatch), + /*4627*/ uint16(xSetOp), uint16(MOVD), + /*4629*/ uint16(xReadSlashR), + /*4630*/ uint16(xArgMm), + /*4631*/ uint16(xArgRM32), + /*4632*/ uint16(xMatch), + /*4633*/ uint16(xCondDataSize), 4637, 4643, 0, + /*4637*/ uint16(xSetOp), uint16(MOVD), + /*4639*/ uint16(xReadSlashR), + /*4640*/ uint16(xArgXmm), + /*4641*/ uint16(xArgRM32), + /*4642*/ uint16(xMatch), + /*4643*/ uint16(xSetOp), uint16(MOVD), + /*4645*/ uint16(xReadSlashR), + /*4646*/ uint16(xArgXmm), + /*4647*/ uint16(xArgRM32), + /*4648*/ uint16(xMatch), + /*4649*/ uint16(xCondPrefix), 2, + 0x66, 4665, + 0x0, 4655, + /*4655*/ uint16(xCondDataSize), 4621, 4627, 4659, + /*4659*/ uint16(xSetOp), uint16(MOVQ), + /*4661*/ uint16(xReadSlashR), + /*4662*/ uint16(xArgMm), + /*4663*/ uint16(xArgRM64), + /*4664*/ uint16(xMatch), + /*4665*/ uint16(xCondDataSize), 4637, 4643, 4669, + /*4669*/ uint16(xSetOp), uint16(MOVQ), + /*4671*/ uint16(xReadSlashR), + /*4672*/ uint16(xArgXmm), + /*4673*/ uint16(xArgRM64), + /*4674*/ uint16(xMatch), + /*4675*/ uint16(xCondPrefix), 3, + 0xF3, 4695, + 0x66, 4689, + 0x0, 4683, + /*4683*/ uint16(xSetOp), uint16(MOVQ), + /*4685*/ uint16(xReadSlashR), + /*4686*/ uint16(xArgMm), + /*4687*/ uint16(xArgMmM64), + /*4688*/ uint16(xMatch), + /*4689*/ uint16(xSetOp), uint16(MOVDQA), + /*4691*/ uint16(xReadSlashR), + /*4692*/ uint16(xArgXmm1), + /*4693*/ uint16(xArgXmm2M128), + /*4694*/ uint16(xMatch), + /*4695*/ uint16(xSetOp), uint16(MOVDQU), + /*4697*/ uint16(xReadSlashR), + /*4698*/ uint16(xArgXmm1), + /*4699*/ uint16(xArgXmm2M128), + /*4700*/ uint16(xMatch), + /*4701*/ uint16(xCondPrefix), 4, + 0xF3, 4735, + 0xF2, 4727, + 0x66, 4719, + 0x0, 4711, + /*4711*/ uint16(xSetOp), uint16(PSHUFW), + /*4713*/ uint16(xReadSlashR), + /*4714*/ uint16(xReadIb), + /*4715*/ uint16(xArgMm1), + /*4716*/ uint16(xArgMm2M64), + /*4717*/ uint16(xArgImm8u), + /*4718*/ uint16(xMatch), + /*4719*/ uint16(xSetOp), uint16(PSHUFD), + /*4721*/ uint16(xReadSlashR), + /*4722*/ uint16(xReadIb), + /*4723*/ uint16(xArgXmm1), + /*4724*/ uint16(xArgXmm2M128), + /*4725*/ uint16(xArgImm8u), + /*4726*/ uint16(xMatch), + /*4727*/ uint16(xSetOp), uint16(PSHUFLW), + /*4729*/ uint16(xReadSlashR), + /*4730*/ uint16(xReadIb), + /*4731*/ uint16(xArgXmm1), + /*4732*/ uint16(xArgXmm2M128), + /*4733*/ uint16(xArgImm8u), + /*4734*/ uint16(xMatch), + /*4735*/ uint16(xSetOp), uint16(PSHUFHW), + /*4737*/ uint16(xReadSlashR), + /*4738*/ uint16(xReadIb), + /*4739*/ uint16(xArgXmm1), + /*4740*/ uint16(xArgXmm2M128), + /*4741*/ uint16(xArgImm8u), + /*4742*/ uint16(xMatch), + /*4743*/ uint16(xCondSlashR), + 0, // 0 + 0, // 1 + 4752, // 2 + 0, // 3 + 4770, // 4 + 0, // 5 + 4788, // 6 + 0, // 7 + /*4752*/ uint16(xCondPrefix), 2, + 0x66, 4764, + 0x0, 4758, + /*4758*/ uint16(xSetOp), uint16(PSRLW), + /*4760*/ uint16(xReadIb), + /*4761*/ uint16(xArgMm2), + /*4762*/ uint16(xArgImm8u), + /*4763*/ uint16(xMatch), + /*4764*/ uint16(xSetOp), uint16(PSRLW), + /*4766*/ uint16(xReadIb), + /*4767*/ uint16(xArgXmm2), + /*4768*/ uint16(xArgImm8u), + /*4769*/ uint16(xMatch), + /*4770*/ uint16(xCondPrefix), 2, + 0x66, 4782, + 0x0, 4776, + /*4776*/ uint16(xSetOp), uint16(PSRAW), + /*4778*/ uint16(xReadIb), + /*4779*/ uint16(xArgMm2), + /*4780*/ uint16(xArgImm8u), + /*4781*/ uint16(xMatch), + /*4782*/ uint16(xSetOp), uint16(PSRAW), + /*4784*/ uint16(xReadIb), + /*4785*/ uint16(xArgXmm2), + /*4786*/ uint16(xArgImm8u), + /*4787*/ uint16(xMatch), + /*4788*/ uint16(xCondPrefix), 2, + 0x66, 4800, + 0x0, 4794, + /*4794*/ uint16(xSetOp), uint16(PSLLW), + /*4796*/ uint16(xReadIb), + /*4797*/ uint16(xArgMm2), + /*4798*/ uint16(xArgImm8u), + /*4799*/ uint16(xMatch), + /*4800*/ uint16(xSetOp), uint16(PSLLW), + /*4802*/ uint16(xReadIb), + /*4803*/ uint16(xArgXmm2), + /*4804*/ uint16(xArgImm8u), + /*4805*/ uint16(xMatch), + /*4806*/ uint16(xCondSlashR), + 0, // 0 + 0, // 1 + 4815, // 2 + 0, // 3 + 4833, // 4 + 0, // 5 + 4851, // 6 + 0, // 7 + /*4815*/ uint16(xCondPrefix), 2, + 0x66, 4827, + 0x0, 4821, + /*4821*/ uint16(xSetOp), uint16(PSRLD), + /*4823*/ uint16(xReadIb), + /*4824*/ uint16(xArgMm2), + /*4825*/ uint16(xArgImm8u), + /*4826*/ uint16(xMatch), + /*4827*/ uint16(xSetOp), uint16(PSRLD), + /*4829*/ uint16(xReadIb), + /*4830*/ uint16(xArgXmm2), + /*4831*/ uint16(xArgImm8u), + /*4832*/ uint16(xMatch), + /*4833*/ uint16(xCondPrefix), 2, + 0x66, 4845, + 0x0, 4839, + /*4839*/ uint16(xSetOp), uint16(PSRAD), + /*4841*/ uint16(xReadIb), + /*4842*/ uint16(xArgMm2), + /*4843*/ uint16(xArgImm8u), + /*4844*/ uint16(xMatch), + /*4845*/ uint16(xSetOp), uint16(PSRAD), + /*4847*/ uint16(xReadIb), + /*4848*/ uint16(xArgXmm2), + /*4849*/ uint16(xArgImm8u), + /*4850*/ uint16(xMatch), + /*4851*/ uint16(xCondPrefix), 2, + 0x66, 4863, + 0x0, 4857, + /*4857*/ uint16(xSetOp), uint16(PSLLD), + /*4859*/ uint16(xReadIb), + /*4860*/ uint16(xArgMm2), + /*4861*/ uint16(xArgImm8u), + /*4862*/ uint16(xMatch), + /*4863*/ uint16(xSetOp), uint16(PSLLD), + /*4865*/ uint16(xReadIb), + /*4866*/ uint16(xArgXmm2), + /*4867*/ uint16(xArgImm8u), + /*4868*/ uint16(xMatch), + /*4869*/ uint16(xCondSlashR), + 0, // 0 + 0, // 1 + 4878, // 2 + 4896, // 3 + 0, // 4 + 0, // 5 + 4906, // 6 + 4924, // 7 + /*4878*/ uint16(xCondPrefix), 2, + 0x66, 4890, + 0x0, 4884, + /*4884*/ uint16(xSetOp), uint16(PSRLQ), + /*4886*/ uint16(xReadIb), + /*4887*/ uint16(xArgMm2), + /*4888*/ uint16(xArgImm8u), + /*4889*/ uint16(xMatch), + /*4890*/ uint16(xSetOp), uint16(PSRLQ), + /*4892*/ uint16(xReadIb), + /*4893*/ uint16(xArgXmm2), + /*4894*/ uint16(xArgImm8u), + /*4895*/ uint16(xMatch), + /*4896*/ uint16(xCondPrefix), 1, + 0x66, 4900, + /*4900*/ uint16(xSetOp), uint16(PSRLDQ), + /*4902*/ uint16(xReadIb), + /*4903*/ uint16(xArgXmm2), + /*4904*/ uint16(xArgImm8u), + /*4905*/ uint16(xMatch), + /*4906*/ uint16(xCondPrefix), 2, + 0x66, 4918, + 0x0, 4912, + /*4912*/ uint16(xSetOp), uint16(PSLLQ), + /*4914*/ uint16(xReadIb), + /*4915*/ uint16(xArgMm2), + /*4916*/ uint16(xArgImm8u), + /*4917*/ uint16(xMatch), + /*4918*/ uint16(xSetOp), uint16(PSLLQ), + /*4920*/ uint16(xReadIb), + /*4921*/ uint16(xArgXmm2), + /*4922*/ uint16(xArgImm8u), + /*4923*/ uint16(xMatch), + /*4924*/ uint16(xCondPrefix), 1, + 0x66, 4928, + /*4928*/ uint16(xSetOp), uint16(PSLLDQ), + /*4930*/ uint16(xReadIb), + /*4931*/ uint16(xArgXmm2), + /*4932*/ uint16(xArgImm8u), + /*4933*/ uint16(xMatch), + /*4934*/ uint16(xCondPrefix), 2, + 0x66, 4946, + 0x0, 4940, + /*4940*/ uint16(xSetOp), uint16(PCMPEQB), + /*4942*/ uint16(xReadSlashR), + /*4943*/ uint16(xArgMm), + /*4944*/ uint16(xArgMmM64), + /*4945*/ uint16(xMatch), + /*4946*/ uint16(xSetOp), uint16(PCMPEQB), + /*4948*/ uint16(xReadSlashR), + /*4949*/ uint16(xArgXmm1), + /*4950*/ uint16(xArgXmm2M128), + /*4951*/ uint16(xMatch), + /*4952*/ uint16(xCondPrefix), 2, + 0x66, 4964, + 0x0, 4958, + /*4958*/ uint16(xSetOp), uint16(PCMPEQW), + /*4960*/ uint16(xReadSlashR), + /*4961*/ uint16(xArgMm), + /*4962*/ uint16(xArgMmM64), + /*4963*/ uint16(xMatch), + /*4964*/ uint16(xSetOp), uint16(PCMPEQW), + /*4966*/ uint16(xReadSlashR), + /*4967*/ uint16(xArgXmm1), + /*4968*/ uint16(xArgXmm2M128), + /*4969*/ uint16(xMatch), + /*4970*/ uint16(xCondPrefix), 2, + 0x66, 4982, + 0x0, 4976, + /*4976*/ uint16(xSetOp), uint16(PCMPEQD), + /*4978*/ uint16(xReadSlashR), + /*4979*/ uint16(xArgMm), + /*4980*/ uint16(xArgMmM64), + /*4981*/ uint16(xMatch), + /*4982*/ uint16(xSetOp), uint16(PCMPEQD), + /*4984*/ uint16(xReadSlashR), + /*4985*/ uint16(xArgXmm1), + /*4986*/ uint16(xArgXmm2M128), + /*4987*/ uint16(xMatch), + /*4988*/ uint16(xSetOp), uint16(EMMS), + /*4990*/ uint16(xMatch), + /*4991*/ uint16(xCondPrefix), 2, + 0xF2, 5003, + 0x66, 4997, + /*4997*/ uint16(xSetOp), uint16(HADDPD), + /*4999*/ uint16(xReadSlashR), + /*5000*/ uint16(xArgXmm1), + /*5001*/ uint16(xArgXmm2M128), + /*5002*/ uint16(xMatch), + /*5003*/ uint16(xSetOp), uint16(HADDPS), + /*5005*/ uint16(xReadSlashR), + /*5006*/ uint16(xArgXmm1), + /*5007*/ uint16(xArgXmm2M128), + /*5008*/ uint16(xMatch), + /*5009*/ uint16(xCondPrefix), 2, + 0xF2, 5021, + 0x66, 5015, + /*5015*/ uint16(xSetOp), uint16(HSUBPD), + /*5017*/ uint16(xReadSlashR), + /*5018*/ uint16(xArgXmm1), + /*5019*/ uint16(xArgXmm2M128), + /*5020*/ uint16(xMatch), + /*5021*/ uint16(xSetOp), uint16(HSUBPS), + /*5023*/ uint16(xReadSlashR), + /*5024*/ uint16(xArgXmm1), + /*5025*/ uint16(xArgXmm2M128), + /*5026*/ uint16(xMatch), + /*5027*/ uint16(xCondIs64), 5030, 5076, + /*5030*/ uint16(xCondPrefix), 3, + 0xF3, 5070, + 0x66, 5054, + 0x0, 5038, + /*5038*/ uint16(xCondDataSize), 5042, 5048, 0, + /*5042*/ uint16(xSetOp), uint16(MOVD), + /*5044*/ uint16(xReadSlashR), + /*5045*/ uint16(xArgRM32), + /*5046*/ uint16(xArgMm), + /*5047*/ uint16(xMatch), + /*5048*/ uint16(xSetOp), uint16(MOVD), + /*5050*/ uint16(xReadSlashR), + /*5051*/ uint16(xArgRM32), + /*5052*/ uint16(xArgMm), + /*5053*/ uint16(xMatch), + /*5054*/ uint16(xCondDataSize), 5058, 5064, 0, + /*5058*/ uint16(xSetOp), uint16(MOVD), + /*5060*/ uint16(xReadSlashR), + /*5061*/ uint16(xArgRM32), + /*5062*/ uint16(xArgXmm), + /*5063*/ uint16(xMatch), + /*5064*/ uint16(xSetOp), uint16(MOVD), + /*5066*/ uint16(xReadSlashR), + /*5067*/ uint16(xArgRM32), + /*5068*/ uint16(xArgXmm), + /*5069*/ uint16(xMatch), + /*5070*/ uint16(xSetOp), uint16(MOVQ), + /*5072*/ uint16(xReadSlashR), + /*5073*/ uint16(xArgXmm1), + /*5074*/ uint16(xArgXmm2M64), + /*5075*/ uint16(xMatch), + /*5076*/ uint16(xCondPrefix), 3, + 0xF3, 5070, + 0x66, 5094, + 0x0, 5084, + /*5084*/ uint16(xCondDataSize), 5042, 5048, 5088, + /*5088*/ uint16(xSetOp), uint16(MOVQ), + /*5090*/ uint16(xReadSlashR), + /*5091*/ uint16(xArgRM64), + /*5092*/ uint16(xArgMm), + /*5093*/ uint16(xMatch), + /*5094*/ uint16(xCondDataSize), 5058, 5064, 5098, + /*5098*/ uint16(xSetOp), uint16(MOVQ), + /*5100*/ uint16(xReadSlashR), + /*5101*/ uint16(xArgRM64), + /*5102*/ uint16(xArgXmm), + /*5103*/ uint16(xMatch), + /*5104*/ uint16(xCondPrefix), 3, + 0xF3, 5124, + 0x66, 5118, + 0x0, 5112, + /*5112*/ uint16(xSetOp), uint16(MOVQ), + /*5114*/ uint16(xReadSlashR), + /*5115*/ uint16(xArgMmM64), + /*5116*/ uint16(xArgMm), + /*5117*/ uint16(xMatch), + /*5118*/ uint16(xSetOp), uint16(MOVDQA), + /*5120*/ uint16(xReadSlashR), + /*5121*/ uint16(xArgXmm2M128), + /*5122*/ uint16(xArgXmm1), + /*5123*/ uint16(xMatch), + /*5124*/ uint16(xSetOp), uint16(MOVDQU), + /*5126*/ uint16(xReadSlashR), + /*5127*/ uint16(xArgXmm2M128), + /*5128*/ uint16(xArgXmm1), + /*5129*/ uint16(xMatch), + /*5130*/ uint16(xCondIs64), 5133, 5147, + /*5133*/ uint16(xCondDataSize), 5137, 5142, 0, + /*5137*/ uint16(xSetOp), uint16(JO), + /*5139*/ uint16(xReadCw), + /*5140*/ uint16(xArgRel16), + /*5141*/ uint16(xMatch), + /*5142*/ uint16(xSetOp), uint16(JO), + /*5144*/ uint16(xReadCd), + /*5145*/ uint16(xArgRel32), + /*5146*/ uint16(xMatch), + /*5147*/ uint16(xCondDataSize), 5151, 5142, 5156, + /*5151*/ uint16(xSetOp), uint16(JO), + /*5153*/ uint16(xReadCd), + /*5154*/ uint16(xArgRel32), + /*5155*/ uint16(xMatch), + /*5156*/ uint16(xSetOp), uint16(JO), + /*5158*/ uint16(xReadCd), + /*5159*/ uint16(xArgRel32), + /*5160*/ uint16(xMatch), + /*5161*/ uint16(xCondIs64), 5164, 5178, + /*5164*/ uint16(xCondDataSize), 5168, 5173, 0, + /*5168*/ uint16(xSetOp), uint16(JNO), + /*5170*/ uint16(xReadCw), + /*5171*/ uint16(xArgRel16), + /*5172*/ uint16(xMatch), + /*5173*/ uint16(xSetOp), uint16(JNO), + /*5175*/ uint16(xReadCd), + /*5176*/ uint16(xArgRel32), + /*5177*/ uint16(xMatch), + /*5178*/ uint16(xCondDataSize), 5182, 5173, 5187, + /*5182*/ uint16(xSetOp), uint16(JNO), + /*5184*/ uint16(xReadCd), + /*5185*/ uint16(xArgRel32), + /*5186*/ uint16(xMatch), + /*5187*/ uint16(xSetOp), uint16(JNO), + /*5189*/ uint16(xReadCd), + /*5190*/ uint16(xArgRel32), + /*5191*/ uint16(xMatch), + /*5192*/ uint16(xCondIs64), 5195, 5209, + /*5195*/ uint16(xCondDataSize), 5199, 5204, 0, + /*5199*/ uint16(xSetOp), uint16(JB), + /*5201*/ uint16(xReadCw), + /*5202*/ uint16(xArgRel16), + /*5203*/ uint16(xMatch), + /*5204*/ uint16(xSetOp), uint16(JB), + /*5206*/ uint16(xReadCd), + /*5207*/ uint16(xArgRel32), + /*5208*/ uint16(xMatch), + /*5209*/ uint16(xCondDataSize), 5213, 5204, 5218, + /*5213*/ uint16(xSetOp), uint16(JB), + /*5215*/ uint16(xReadCd), + /*5216*/ uint16(xArgRel32), + /*5217*/ uint16(xMatch), + /*5218*/ uint16(xSetOp), uint16(JB), + /*5220*/ uint16(xReadCd), + /*5221*/ uint16(xArgRel32), + /*5222*/ uint16(xMatch), + /*5223*/ uint16(xCondIs64), 5226, 5240, + /*5226*/ uint16(xCondDataSize), 5230, 5235, 0, + /*5230*/ uint16(xSetOp), uint16(JAE), + /*5232*/ uint16(xReadCw), + /*5233*/ uint16(xArgRel16), + /*5234*/ uint16(xMatch), + /*5235*/ uint16(xSetOp), uint16(JAE), + /*5237*/ uint16(xReadCd), + /*5238*/ uint16(xArgRel32), + /*5239*/ uint16(xMatch), + /*5240*/ uint16(xCondDataSize), 5244, 5235, 5249, + /*5244*/ uint16(xSetOp), uint16(JAE), + /*5246*/ uint16(xReadCd), + /*5247*/ uint16(xArgRel32), + /*5248*/ uint16(xMatch), + /*5249*/ uint16(xSetOp), uint16(JAE), + /*5251*/ uint16(xReadCd), + /*5252*/ uint16(xArgRel32), + /*5253*/ uint16(xMatch), + /*5254*/ uint16(xCondIs64), 5257, 5271, + /*5257*/ uint16(xCondDataSize), 5261, 5266, 0, + /*5261*/ uint16(xSetOp), uint16(JE), + /*5263*/ uint16(xReadCw), + /*5264*/ uint16(xArgRel16), + /*5265*/ uint16(xMatch), + /*5266*/ uint16(xSetOp), uint16(JE), + /*5268*/ uint16(xReadCd), + /*5269*/ uint16(xArgRel32), + /*5270*/ uint16(xMatch), + /*5271*/ uint16(xCondDataSize), 5275, 5266, 5280, + /*5275*/ uint16(xSetOp), uint16(JE), + /*5277*/ uint16(xReadCd), + /*5278*/ uint16(xArgRel32), + /*5279*/ uint16(xMatch), + /*5280*/ uint16(xSetOp), uint16(JE), + /*5282*/ uint16(xReadCd), + /*5283*/ uint16(xArgRel32), + /*5284*/ uint16(xMatch), + /*5285*/ uint16(xCondIs64), 5288, 5302, + /*5288*/ uint16(xCondDataSize), 5292, 5297, 0, + /*5292*/ uint16(xSetOp), uint16(JNE), + /*5294*/ uint16(xReadCw), + /*5295*/ uint16(xArgRel16), + /*5296*/ uint16(xMatch), + /*5297*/ uint16(xSetOp), uint16(JNE), + /*5299*/ uint16(xReadCd), + /*5300*/ uint16(xArgRel32), + /*5301*/ uint16(xMatch), + /*5302*/ uint16(xCondDataSize), 5306, 5297, 5311, + /*5306*/ uint16(xSetOp), uint16(JNE), + /*5308*/ uint16(xReadCd), + /*5309*/ uint16(xArgRel32), + /*5310*/ uint16(xMatch), + /*5311*/ uint16(xSetOp), uint16(JNE), + /*5313*/ uint16(xReadCd), + /*5314*/ uint16(xArgRel32), + /*5315*/ uint16(xMatch), + /*5316*/ uint16(xCondIs64), 5319, 5333, + /*5319*/ uint16(xCondDataSize), 5323, 5328, 0, + /*5323*/ uint16(xSetOp), uint16(JBE), + /*5325*/ uint16(xReadCw), + /*5326*/ uint16(xArgRel16), + /*5327*/ uint16(xMatch), + /*5328*/ uint16(xSetOp), uint16(JBE), + /*5330*/ uint16(xReadCd), + /*5331*/ uint16(xArgRel32), + /*5332*/ uint16(xMatch), + /*5333*/ uint16(xCondDataSize), 5337, 5328, 5342, + /*5337*/ uint16(xSetOp), uint16(JBE), + /*5339*/ uint16(xReadCd), + /*5340*/ uint16(xArgRel32), + /*5341*/ uint16(xMatch), + /*5342*/ uint16(xSetOp), uint16(JBE), + /*5344*/ uint16(xReadCd), + /*5345*/ uint16(xArgRel32), + /*5346*/ uint16(xMatch), + /*5347*/ uint16(xCondIs64), 5350, 5364, + /*5350*/ uint16(xCondDataSize), 5354, 5359, 0, + /*5354*/ uint16(xSetOp), uint16(JA), + /*5356*/ uint16(xReadCw), + /*5357*/ uint16(xArgRel16), + /*5358*/ uint16(xMatch), + /*5359*/ uint16(xSetOp), uint16(JA), + /*5361*/ uint16(xReadCd), + /*5362*/ uint16(xArgRel32), + /*5363*/ uint16(xMatch), + /*5364*/ uint16(xCondDataSize), 5368, 5359, 5373, + /*5368*/ uint16(xSetOp), uint16(JA), + /*5370*/ uint16(xReadCd), + /*5371*/ uint16(xArgRel32), + /*5372*/ uint16(xMatch), + /*5373*/ uint16(xSetOp), uint16(JA), + /*5375*/ uint16(xReadCd), + /*5376*/ uint16(xArgRel32), + /*5377*/ uint16(xMatch), + /*5378*/ uint16(xCondIs64), 5381, 5395, + /*5381*/ uint16(xCondDataSize), 5385, 5390, 0, + /*5385*/ uint16(xSetOp), uint16(JS), + /*5387*/ uint16(xReadCw), + /*5388*/ uint16(xArgRel16), + /*5389*/ uint16(xMatch), + /*5390*/ uint16(xSetOp), uint16(JS), + /*5392*/ uint16(xReadCd), + /*5393*/ uint16(xArgRel32), + /*5394*/ uint16(xMatch), + /*5395*/ uint16(xCondDataSize), 5399, 5390, 5404, + /*5399*/ uint16(xSetOp), uint16(JS), + /*5401*/ uint16(xReadCd), + /*5402*/ uint16(xArgRel32), + /*5403*/ uint16(xMatch), + /*5404*/ uint16(xSetOp), uint16(JS), + /*5406*/ uint16(xReadCd), + /*5407*/ uint16(xArgRel32), + /*5408*/ uint16(xMatch), + /*5409*/ uint16(xCondIs64), 5412, 5426, + /*5412*/ uint16(xCondDataSize), 5416, 5421, 0, + /*5416*/ uint16(xSetOp), uint16(JNS), + /*5418*/ uint16(xReadCw), + /*5419*/ uint16(xArgRel16), + /*5420*/ uint16(xMatch), + /*5421*/ uint16(xSetOp), uint16(JNS), + /*5423*/ uint16(xReadCd), + /*5424*/ uint16(xArgRel32), + /*5425*/ uint16(xMatch), + /*5426*/ uint16(xCondDataSize), 5430, 5421, 5435, + /*5430*/ uint16(xSetOp), uint16(JNS), + /*5432*/ uint16(xReadCd), + /*5433*/ uint16(xArgRel32), + /*5434*/ uint16(xMatch), + /*5435*/ uint16(xSetOp), uint16(JNS), + /*5437*/ uint16(xReadCd), + /*5438*/ uint16(xArgRel32), + /*5439*/ uint16(xMatch), + /*5440*/ uint16(xCondIs64), 5443, 5457, + /*5443*/ uint16(xCondDataSize), 5447, 5452, 0, + /*5447*/ uint16(xSetOp), uint16(JP), + /*5449*/ uint16(xReadCw), + /*5450*/ uint16(xArgRel16), + /*5451*/ uint16(xMatch), + /*5452*/ uint16(xSetOp), uint16(JP), + /*5454*/ uint16(xReadCd), + /*5455*/ uint16(xArgRel32), + /*5456*/ uint16(xMatch), + /*5457*/ uint16(xCondDataSize), 5461, 5452, 5466, + /*5461*/ uint16(xSetOp), uint16(JP), + /*5463*/ uint16(xReadCd), + /*5464*/ uint16(xArgRel32), + /*5465*/ uint16(xMatch), + /*5466*/ uint16(xSetOp), uint16(JP), + /*5468*/ uint16(xReadCd), + /*5469*/ uint16(xArgRel32), + /*5470*/ uint16(xMatch), + /*5471*/ uint16(xCondIs64), 5474, 5488, + /*5474*/ uint16(xCondDataSize), 5478, 5483, 0, + /*5478*/ uint16(xSetOp), uint16(JNP), + /*5480*/ uint16(xReadCw), + /*5481*/ uint16(xArgRel16), + /*5482*/ uint16(xMatch), + /*5483*/ uint16(xSetOp), uint16(JNP), + /*5485*/ uint16(xReadCd), + /*5486*/ uint16(xArgRel32), + /*5487*/ uint16(xMatch), + /*5488*/ uint16(xCondDataSize), 5492, 5483, 5497, + /*5492*/ uint16(xSetOp), uint16(JNP), + /*5494*/ uint16(xReadCd), + /*5495*/ uint16(xArgRel32), + /*5496*/ uint16(xMatch), + /*5497*/ uint16(xSetOp), uint16(JNP), + /*5499*/ uint16(xReadCd), + /*5500*/ uint16(xArgRel32), + /*5501*/ uint16(xMatch), + /*5502*/ uint16(xCondIs64), 5505, 5519, + /*5505*/ uint16(xCondDataSize), 5509, 5514, 0, + /*5509*/ uint16(xSetOp), uint16(JL), + /*5511*/ uint16(xReadCw), + /*5512*/ uint16(xArgRel16), + /*5513*/ uint16(xMatch), + /*5514*/ uint16(xSetOp), uint16(JL), + /*5516*/ uint16(xReadCd), + /*5517*/ uint16(xArgRel32), + /*5518*/ uint16(xMatch), + /*5519*/ uint16(xCondDataSize), 5523, 5514, 5528, + /*5523*/ uint16(xSetOp), uint16(JL), + /*5525*/ uint16(xReadCd), + /*5526*/ uint16(xArgRel32), + /*5527*/ uint16(xMatch), + /*5528*/ uint16(xSetOp), uint16(JL), + /*5530*/ uint16(xReadCd), + /*5531*/ uint16(xArgRel32), + /*5532*/ uint16(xMatch), + /*5533*/ uint16(xCondIs64), 5536, 5550, + /*5536*/ uint16(xCondDataSize), 5540, 5545, 0, + /*5540*/ uint16(xSetOp), uint16(JGE), + /*5542*/ uint16(xReadCw), + /*5543*/ uint16(xArgRel16), + /*5544*/ uint16(xMatch), + /*5545*/ uint16(xSetOp), uint16(JGE), + /*5547*/ uint16(xReadCd), + /*5548*/ uint16(xArgRel32), + /*5549*/ uint16(xMatch), + /*5550*/ uint16(xCondDataSize), 5554, 5545, 5559, + /*5554*/ uint16(xSetOp), uint16(JGE), + /*5556*/ uint16(xReadCd), + /*5557*/ uint16(xArgRel32), + /*5558*/ uint16(xMatch), + /*5559*/ uint16(xSetOp), uint16(JGE), + /*5561*/ uint16(xReadCd), + /*5562*/ uint16(xArgRel32), + /*5563*/ uint16(xMatch), + /*5564*/ uint16(xCondIs64), 5567, 5581, + /*5567*/ uint16(xCondDataSize), 5571, 5576, 0, + /*5571*/ uint16(xSetOp), uint16(JLE), + /*5573*/ uint16(xReadCw), + /*5574*/ uint16(xArgRel16), + /*5575*/ uint16(xMatch), + /*5576*/ uint16(xSetOp), uint16(JLE), + /*5578*/ uint16(xReadCd), + /*5579*/ uint16(xArgRel32), + /*5580*/ uint16(xMatch), + /*5581*/ uint16(xCondDataSize), 5585, 5576, 5590, + /*5585*/ uint16(xSetOp), uint16(JLE), + /*5587*/ uint16(xReadCd), + /*5588*/ uint16(xArgRel32), + /*5589*/ uint16(xMatch), + /*5590*/ uint16(xSetOp), uint16(JLE), + /*5592*/ uint16(xReadCd), + /*5593*/ uint16(xArgRel32), + /*5594*/ uint16(xMatch), + /*5595*/ uint16(xCondIs64), 5598, 5612, + /*5598*/ uint16(xCondDataSize), 5602, 5607, 0, + /*5602*/ uint16(xSetOp), uint16(JG), + /*5604*/ uint16(xReadCw), + /*5605*/ uint16(xArgRel16), + /*5606*/ uint16(xMatch), + /*5607*/ uint16(xSetOp), uint16(JG), + /*5609*/ uint16(xReadCd), + /*5610*/ uint16(xArgRel32), + /*5611*/ uint16(xMatch), + /*5612*/ uint16(xCondDataSize), 5616, 5607, 5621, + /*5616*/ uint16(xSetOp), uint16(JG), + /*5618*/ uint16(xReadCd), + /*5619*/ uint16(xArgRel32), + /*5620*/ uint16(xMatch), + /*5621*/ uint16(xSetOp), uint16(JG), + /*5623*/ uint16(xReadCd), + /*5624*/ uint16(xArgRel32), + /*5625*/ uint16(xMatch), + /*5626*/ uint16(xSetOp), uint16(SETO), + /*5628*/ uint16(xReadSlashR), + /*5629*/ uint16(xArgRM8), + /*5630*/ uint16(xMatch), + /*5631*/ uint16(xSetOp), uint16(SETNO), + /*5633*/ uint16(xReadSlashR), + /*5634*/ uint16(xArgRM8), + /*5635*/ uint16(xMatch), + /*5636*/ uint16(xSetOp), uint16(SETB), + /*5638*/ uint16(xReadSlashR), + /*5639*/ uint16(xArgRM8), + /*5640*/ uint16(xMatch), + /*5641*/ uint16(xSetOp), uint16(SETAE), + /*5643*/ uint16(xReadSlashR), + /*5644*/ uint16(xArgRM8), + /*5645*/ uint16(xMatch), + /*5646*/ uint16(xSetOp), uint16(SETE), + /*5648*/ uint16(xReadSlashR), + /*5649*/ uint16(xArgRM8), + /*5650*/ uint16(xMatch), + /*5651*/ uint16(xSetOp), uint16(SETNE), + /*5653*/ uint16(xReadSlashR), + /*5654*/ uint16(xArgRM8), + /*5655*/ uint16(xMatch), + /*5656*/ uint16(xSetOp), uint16(SETBE), + /*5658*/ uint16(xReadSlashR), + /*5659*/ uint16(xArgRM8), + /*5660*/ uint16(xMatch), + /*5661*/ uint16(xSetOp), uint16(SETA), + /*5663*/ uint16(xReadSlashR), + /*5664*/ uint16(xArgRM8), + /*5665*/ uint16(xMatch), + /*5666*/ uint16(xSetOp), uint16(SETS), + /*5668*/ uint16(xReadSlashR), + /*5669*/ uint16(xArgRM8), + /*5670*/ uint16(xMatch), + /*5671*/ uint16(xSetOp), uint16(SETNS), + /*5673*/ uint16(xReadSlashR), + /*5674*/ uint16(xArgRM8), + /*5675*/ uint16(xMatch), + /*5676*/ uint16(xSetOp), uint16(SETP), + /*5678*/ uint16(xReadSlashR), + /*5679*/ uint16(xArgRM8), + /*5680*/ uint16(xMatch), + /*5681*/ uint16(xSetOp), uint16(SETNP), + /*5683*/ uint16(xReadSlashR), + /*5684*/ uint16(xArgRM8), + /*5685*/ uint16(xMatch), + /*5686*/ uint16(xSetOp), uint16(SETL), + /*5688*/ uint16(xReadSlashR), + /*5689*/ uint16(xArgRM8), + /*5690*/ uint16(xMatch), + /*5691*/ uint16(xSetOp), uint16(SETGE), + /*5693*/ uint16(xReadSlashR), + /*5694*/ uint16(xArgRM8), + /*5695*/ uint16(xMatch), + /*5696*/ uint16(xSetOp), uint16(SETLE), + /*5698*/ uint16(xReadSlashR), + /*5699*/ uint16(xArgRM8), + /*5700*/ uint16(xMatch), + /*5701*/ uint16(xSetOp), uint16(SETG), + /*5703*/ uint16(xReadSlashR), + /*5704*/ uint16(xArgRM8), + /*5705*/ uint16(xMatch), + /*5706*/ uint16(xSetOp), uint16(PUSH), + /*5708*/ uint16(xArgFS), + /*5709*/ uint16(xMatch), + /*5710*/ uint16(xCondIs64), 5713, 5725, + /*5713*/ uint16(xCondDataSize), 5717, 5721, 0, + /*5717*/ uint16(xSetOp), uint16(POP), + /*5719*/ uint16(xArgFS), + /*5720*/ uint16(xMatch), + /*5721*/ uint16(xSetOp), uint16(POP), + /*5723*/ uint16(xArgFS), + /*5724*/ uint16(xMatch), + /*5725*/ uint16(xCondDataSize), 5717, 5729, 5733, + /*5729*/ uint16(xSetOp), uint16(POP), + /*5731*/ uint16(xArgFS), + /*5732*/ uint16(xMatch), + /*5733*/ uint16(xSetOp), uint16(POP), + /*5735*/ uint16(xArgFS), + /*5736*/ uint16(xMatch), + /*5737*/ uint16(xSetOp), uint16(CPUID), + /*5739*/ uint16(xMatch), + /*5740*/ uint16(xCondIs64), 5743, 5759, + /*5743*/ uint16(xCondDataSize), 5747, 5753, 0, + /*5747*/ uint16(xSetOp), uint16(BT), + /*5749*/ uint16(xReadSlashR), + /*5750*/ uint16(xArgRM16), + /*5751*/ uint16(xArgR16), + /*5752*/ uint16(xMatch), + /*5753*/ uint16(xSetOp), uint16(BT), + /*5755*/ uint16(xReadSlashR), + /*5756*/ uint16(xArgRM32), + /*5757*/ uint16(xArgR32), + /*5758*/ uint16(xMatch), + /*5759*/ uint16(xCondDataSize), 5747, 5753, 5763, + /*5763*/ uint16(xSetOp), uint16(BT), + /*5765*/ uint16(xReadSlashR), + /*5766*/ uint16(xArgRM64), + /*5767*/ uint16(xArgR64), + /*5768*/ uint16(xMatch), + /*5769*/ uint16(xCondIs64), 5772, 5792, + /*5772*/ uint16(xCondDataSize), 5776, 5784, 0, + /*5776*/ uint16(xSetOp), uint16(SHLD), + /*5778*/ uint16(xReadSlashR), + /*5779*/ uint16(xReadIb), + /*5780*/ uint16(xArgRM16), + /*5781*/ uint16(xArgR16), + /*5782*/ uint16(xArgImm8u), + /*5783*/ uint16(xMatch), + /*5784*/ uint16(xSetOp), uint16(SHLD), + /*5786*/ uint16(xReadSlashR), + /*5787*/ uint16(xReadIb), + /*5788*/ uint16(xArgRM32), + /*5789*/ uint16(xArgR32), + /*5790*/ uint16(xArgImm8u), + /*5791*/ uint16(xMatch), + /*5792*/ uint16(xCondDataSize), 5776, 5784, 5796, + /*5796*/ uint16(xSetOp), uint16(SHLD), + /*5798*/ uint16(xReadSlashR), + /*5799*/ uint16(xReadIb), + /*5800*/ uint16(xArgRM64), + /*5801*/ uint16(xArgR64), + /*5802*/ uint16(xArgImm8u), + /*5803*/ uint16(xMatch), + /*5804*/ uint16(xCondIs64), 5807, 5825, + /*5807*/ uint16(xCondDataSize), 5811, 5818, 0, + /*5811*/ uint16(xSetOp), uint16(SHLD), + /*5813*/ uint16(xReadSlashR), + /*5814*/ uint16(xArgRM16), + /*5815*/ uint16(xArgR16), + /*5816*/ uint16(xArgCL), + /*5817*/ uint16(xMatch), + /*5818*/ uint16(xSetOp), uint16(SHLD), + /*5820*/ uint16(xReadSlashR), + /*5821*/ uint16(xArgRM32), + /*5822*/ uint16(xArgR32), + /*5823*/ uint16(xArgCL), + /*5824*/ uint16(xMatch), + /*5825*/ uint16(xCondDataSize), 5811, 5818, 5829, + /*5829*/ uint16(xSetOp), uint16(SHLD), + /*5831*/ uint16(xReadSlashR), + /*5832*/ uint16(xArgRM64), + /*5833*/ uint16(xArgR64), + /*5834*/ uint16(xArgCL), + /*5835*/ uint16(xMatch), + /*5836*/ uint16(xSetOp), uint16(PUSH), + /*5838*/ uint16(xArgGS), + /*5839*/ uint16(xMatch), + /*5840*/ uint16(xCondIs64), 5843, 5855, + /*5843*/ uint16(xCondDataSize), 5847, 5851, 0, + /*5847*/ uint16(xSetOp), uint16(POP), + /*5849*/ uint16(xArgGS), + /*5850*/ uint16(xMatch), + /*5851*/ uint16(xSetOp), uint16(POP), + /*5853*/ uint16(xArgGS), + /*5854*/ uint16(xMatch), + /*5855*/ uint16(xCondDataSize), 5847, 5859, 5863, + /*5859*/ uint16(xSetOp), uint16(POP), + /*5861*/ uint16(xArgGS), + /*5862*/ uint16(xMatch), + /*5863*/ uint16(xSetOp), uint16(POP), + /*5865*/ uint16(xArgGS), + /*5866*/ uint16(xMatch), + /*5867*/ uint16(xSetOp), uint16(RSM), + /*5869*/ uint16(xMatch), + /*5870*/ uint16(xCondIs64), 5873, 5889, + /*5873*/ uint16(xCondDataSize), 5877, 5883, 0, + /*5877*/ uint16(xSetOp), uint16(BTS), + /*5879*/ uint16(xReadSlashR), + /*5880*/ uint16(xArgRM16), + /*5881*/ uint16(xArgR16), + /*5882*/ uint16(xMatch), + /*5883*/ uint16(xSetOp), uint16(BTS), + /*5885*/ uint16(xReadSlashR), + /*5886*/ uint16(xArgRM32), + /*5887*/ uint16(xArgR32), + /*5888*/ uint16(xMatch), + /*5889*/ uint16(xCondDataSize), 5877, 5883, 5893, + /*5893*/ uint16(xSetOp), uint16(BTS), + /*5895*/ uint16(xReadSlashR), + /*5896*/ uint16(xArgRM64), + /*5897*/ uint16(xArgR64), + /*5898*/ uint16(xMatch), + /*5899*/ uint16(xCondIs64), 5902, 5922, + /*5902*/ uint16(xCondDataSize), 5906, 5914, 0, + /*5906*/ uint16(xSetOp), uint16(SHRD), + /*5908*/ uint16(xReadSlashR), + /*5909*/ uint16(xReadIb), + /*5910*/ uint16(xArgRM16), + /*5911*/ uint16(xArgR16), + /*5912*/ uint16(xArgImm8u), + /*5913*/ uint16(xMatch), + /*5914*/ uint16(xSetOp), uint16(SHRD), + /*5916*/ uint16(xReadSlashR), + /*5917*/ uint16(xReadIb), + /*5918*/ uint16(xArgRM32), + /*5919*/ uint16(xArgR32), + /*5920*/ uint16(xArgImm8u), + /*5921*/ uint16(xMatch), + /*5922*/ uint16(xCondDataSize), 5906, 5914, 5926, + /*5926*/ uint16(xSetOp), uint16(SHRD), + /*5928*/ uint16(xReadSlashR), + /*5929*/ uint16(xReadIb), + /*5930*/ uint16(xArgRM64), + /*5931*/ uint16(xArgR64), + /*5932*/ uint16(xArgImm8u), + /*5933*/ uint16(xMatch), + /*5934*/ uint16(xCondIs64), 5937, 5955, + /*5937*/ uint16(xCondDataSize), 5941, 5948, 0, + /*5941*/ uint16(xSetOp), uint16(SHRD), + /*5943*/ uint16(xReadSlashR), + /*5944*/ uint16(xArgRM16), + /*5945*/ uint16(xArgR16), + /*5946*/ uint16(xArgCL), + /*5947*/ uint16(xMatch), + /*5948*/ uint16(xSetOp), uint16(SHRD), + /*5950*/ uint16(xReadSlashR), + /*5951*/ uint16(xArgRM32), + /*5952*/ uint16(xArgR32), + /*5953*/ uint16(xArgCL), + /*5954*/ uint16(xMatch), + /*5955*/ uint16(xCondDataSize), 5941, 5948, 5959, + /*5959*/ uint16(xSetOp), uint16(SHRD), + /*5961*/ uint16(xReadSlashR), + /*5962*/ uint16(xArgRM64), + /*5963*/ uint16(xArgR64), + /*5964*/ uint16(xArgCL), + /*5965*/ uint16(xMatch), + /*5966*/ uint16(xCondByte), 3, + 0xE8, 6215, + 0xF0, 6218, + 0xF8, 6221, + /*5974*/ uint16(xCondSlashR), + 5983, // 0 + 6037, // 1 + 6091, // 2 + 6120, // 3 + 6149, // 4 + 6172, // 5 + 6195, // 6 + 6211, // 7 + /*5983*/ uint16(xCondIs64), 5986, 5998, + /*5986*/ uint16(xCondDataSize), 5990, 5994, 0, + /*5990*/ uint16(xSetOp), uint16(FXSAVE), + /*5992*/ uint16(xArgM512byte), + /*5993*/ uint16(xMatch), + /*5994*/ uint16(xSetOp), uint16(FXSAVE), + /*5996*/ uint16(xArgM512byte), + /*5997*/ uint16(xMatch), + /*5998*/ uint16(xCondPrefix), 2, + 0xF3, 6012, + 0x0, 6004, + /*6004*/ uint16(xCondDataSize), 5990, 5994, 6008, + /*6008*/ uint16(xSetOp), uint16(FXSAVE64), + /*6010*/ uint16(xArgM512byte), + /*6011*/ uint16(xMatch), + /*6012*/ uint16(xCondDataSize), 6016, 6023, 6030, + /*6016*/ uint16(xCondIsMem), 6019, 0, + /*6019*/ uint16(xSetOp), uint16(RDFSBASE), + /*6021*/ uint16(xArgRM32), + /*6022*/ uint16(xMatch), + /*6023*/ uint16(xCondIsMem), 6026, 0, + /*6026*/ uint16(xSetOp), uint16(RDFSBASE), + /*6028*/ uint16(xArgRM32), + /*6029*/ uint16(xMatch), + /*6030*/ uint16(xCondIsMem), 6033, 0, + /*6033*/ uint16(xSetOp), uint16(RDFSBASE), + /*6035*/ uint16(xArgRM64), + /*6036*/ uint16(xMatch), + /*6037*/ uint16(xCondIs64), 6040, 6052, + /*6040*/ uint16(xCondDataSize), 6044, 6048, 0, + /*6044*/ uint16(xSetOp), uint16(FXRSTOR), + /*6046*/ uint16(xArgM512byte), + /*6047*/ uint16(xMatch), + /*6048*/ uint16(xSetOp), uint16(FXRSTOR), + /*6050*/ uint16(xArgM512byte), + /*6051*/ uint16(xMatch), + /*6052*/ uint16(xCondPrefix), 2, + 0xF3, 6066, + 0x0, 6058, + /*6058*/ uint16(xCondDataSize), 6044, 6048, 6062, + /*6062*/ uint16(xSetOp), uint16(FXRSTOR64), + /*6064*/ uint16(xArgM512byte), + /*6065*/ uint16(xMatch), + /*6066*/ uint16(xCondDataSize), 6070, 6077, 6084, + /*6070*/ uint16(xCondIsMem), 6073, 0, + /*6073*/ uint16(xSetOp), uint16(RDGSBASE), + /*6075*/ uint16(xArgRM32), + /*6076*/ uint16(xMatch), + /*6077*/ uint16(xCondIsMem), 6080, 0, + /*6080*/ uint16(xSetOp), uint16(RDGSBASE), + /*6082*/ uint16(xArgRM32), + /*6083*/ uint16(xMatch), + /*6084*/ uint16(xCondIsMem), 6087, 0, + /*6087*/ uint16(xSetOp), uint16(RDGSBASE), + /*6089*/ uint16(xArgRM64), + /*6090*/ uint16(xMatch), + /*6091*/ uint16(xCondIs64), 6094, 6098, + /*6094*/ uint16(xSetOp), uint16(LDMXCSR), + /*6096*/ uint16(xArgM32), + /*6097*/ uint16(xMatch), + /*6098*/ uint16(xCondPrefix), 2, + 0xF3, 6104, + 0x0, 6094, + /*6104*/ uint16(xCondDataSize), 6108, 6112, 6116, + /*6108*/ uint16(xSetOp), uint16(WRFSBASE), + /*6110*/ uint16(xArgRM32), + /*6111*/ uint16(xMatch), + /*6112*/ uint16(xSetOp), uint16(WRFSBASE), + /*6114*/ uint16(xArgRM32), + /*6115*/ uint16(xMatch), + /*6116*/ uint16(xSetOp), uint16(WRFSBASE), + /*6118*/ uint16(xArgRM64), + /*6119*/ uint16(xMatch), + /*6120*/ uint16(xCondIs64), 6123, 6127, + /*6123*/ uint16(xSetOp), uint16(STMXCSR), + /*6125*/ uint16(xArgM32), + /*6126*/ uint16(xMatch), + /*6127*/ uint16(xCondPrefix), 2, + 0xF3, 6133, + 0x0, 6123, + /*6133*/ uint16(xCondDataSize), 6137, 6141, 6145, + /*6137*/ uint16(xSetOp), uint16(WRGSBASE), + /*6139*/ uint16(xArgRM32), + /*6140*/ uint16(xMatch), + /*6141*/ uint16(xSetOp), uint16(WRGSBASE), + /*6143*/ uint16(xArgRM32), + /*6144*/ uint16(xMatch), + /*6145*/ uint16(xSetOp), uint16(WRGSBASE), + /*6147*/ uint16(xArgRM64), + /*6148*/ uint16(xMatch), + /*6149*/ uint16(xCondIs64), 6152, 6164, + /*6152*/ uint16(xCondDataSize), 6156, 6160, 0, + /*6156*/ uint16(xSetOp), uint16(XSAVE), + /*6158*/ uint16(xArgMem), + /*6159*/ uint16(xMatch), + /*6160*/ uint16(xSetOp), uint16(XSAVE), + /*6162*/ uint16(xArgMem), + /*6163*/ uint16(xMatch), + /*6164*/ uint16(xCondDataSize), 6156, 6160, 6168, + /*6168*/ uint16(xSetOp), uint16(XSAVE64), + /*6170*/ uint16(xArgMem), + /*6171*/ uint16(xMatch), + /*6172*/ uint16(xCondIs64), 6175, 6187, + /*6175*/ uint16(xCondDataSize), 6179, 6183, 0, + /*6179*/ uint16(xSetOp), uint16(XRSTOR), + /*6181*/ uint16(xArgMem), + /*6182*/ uint16(xMatch), + /*6183*/ uint16(xSetOp), uint16(XRSTOR), + /*6185*/ uint16(xArgMem), + /*6186*/ uint16(xMatch), + /*6187*/ uint16(xCondDataSize), 6179, 6183, 6191, + /*6191*/ uint16(xSetOp), uint16(XRSTOR64), + /*6193*/ uint16(xArgMem), + /*6194*/ uint16(xMatch), + /*6195*/ uint16(xCondDataSize), 6199, 6203, 6207, + /*6199*/ uint16(xSetOp), uint16(XSAVEOPT), + /*6201*/ uint16(xArgMem), + /*6202*/ uint16(xMatch), + /*6203*/ uint16(xSetOp), uint16(XSAVEOPT), + /*6205*/ uint16(xArgMem), + /*6206*/ uint16(xMatch), + /*6207*/ uint16(xSetOp), uint16(XSAVEOPT64), + /*6209*/ uint16(xArgMem), + /*6210*/ uint16(xMatch), + /*6211*/ uint16(xSetOp), uint16(CLFLUSH), + /*6213*/ uint16(xArgM8), + /*6214*/ uint16(xMatch), + /*6215*/ uint16(xSetOp), uint16(LFENCE), + /*6217*/ uint16(xMatch), + /*6218*/ uint16(xSetOp), uint16(MFENCE), + /*6220*/ uint16(xMatch), + /*6221*/ uint16(xSetOp), uint16(SFENCE), + /*6223*/ uint16(xMatch), + /*6224*/ uint16(xCondIs64), 6227, 6243, + /*6227*/ uint16(xCondDataSize), 6231, 6237, 0, + /*6231*/ uint16(xSetOp), uint16(IMUL), + /*6233*/ uint16(xReadSlashR), + /*6234*/ uint16(xArgR16), + /*6235*/ uint16(xArgRM16), + /*6236*/ uint16(xMatch), + /*6237*/ uint16(xSetOp), uint16(IMUL), + /*6239*/ uint16(xReadSlashR), + /*6240*/ uint16(xArgR32), + /*6241*/ uint16(xArgRM32), + /*6242*/ uint16(xMatch), + /*6243*/ uint16(xCondDataSize), 6231, 6237, 6247, + /*6247*/ uint16(xSetOp), uint16(IMUL), + /*6249*/ uint16(xReadSlashR), + /*6250*/ uint16(xArgR64), + /*6251*/ uint16(xArgRM64), + /*6252*/ uint16(xMatch), + /*6253*/ uint16(xSetOp), uint16(CMPXCHG), + /*6255*/ uint16(xReadSlashR), + /*6256*/ uint16(xArgRM8), + /*6257*/ uint16(xArgR8), + /*6258*/ uint16(xMatch), + /*6259*/ uint16(xCondIs64), 6262, 6278, + /*6262*/ uint16(xCondDataSize), 6266, 6272, 0, + /*6266*/ uint16(xSetOp), uint16(CMPXCHG), + /*6268*/ uint16(xReadSlashR), + /*6269*/ uint16(xArgRM16), + /*6270*/ uint16(xArgR16), + /*6271*/ uint16(xMatch), + /*6272*/ uint16(xSetOp), uint16(CMPXCHG), + /*6274*/ uint16(xReadSlashR), + /*6275*/ uint16(xArgRM32), + /*6276*/ uint16(xArgR32), + /*6277*/ uint16(xMatch), + /*6278*/ uint16(xCondDataSize), 6266, 6272, 6282, + /*6282*/ uint16(xSetOp), uint16(CMPXCHG), + /*6284*/ uint16(xReadSlashR), + /*6285*/ uint16(xArgRM64), + /*6286*/ uint16(xArgR64), + /*6287*/ uint16(xMatch), + /*6288*/ uint16(xCondIs64), 6291, 6307, + /*6291*/ uint16(xCondDataSize), 6295, 6301, 0, + /*6295*/ uint16(xSetOp), uint16(LSS), + /*6297*/ uint16(xReadSlashR), + /*6298*/ uint16(xArgR16), + /*6299*/ uint16(xArgM16colon16), + /*6300*/ uint16(xMatch), + /*6301*/ uint16(xSetOp), uint16(LSS), + /*6303*/ uint16(xReadSlashR), + /*6304*/ uint16(xArgR32), + /*6305*/ uint16(xArgM16colon32), + /*6306*/ uint16(xMatch), + /*6307*/ uint16(xCondDataSize), 6295, 6301, 6311, + /*6311*/ uint16(xSetOp), uint16(LSS), + /*6313*/ uint16(xReadSlashR), + /*6314*/ uint16(xArgR64), + /*6315*/ uint16(xArgM16colon64), + /*6316*/ uint16(xMatch), + /*6317*/ uint16(xCondIs64), 6320, 6336, + /*6320*/ uint16(xCondDataSize), 6324, 6330, 0, + /*6324*/ uint16(xSetOp), uint16(BTR), + /*6326*/ uint16(xReadSlashR), + /*6327*/ uint16(xArgRM16), + /*6328*/ uint16(xArgR16), + /*6329*/ uint16(xMatch), + /*6330*/ uint16(xSetOp), uint16(BTR), + /*6332*/ uint16(xReadSlashR), + /*6333*/ uint16(xArgRM32), + /*6334*/ uint16(xArgR32), + /*6335*/ uint16(xMatch), + /*6336*/ uint16(xCondDataSize), 6324, 6330, 6340, + /*6340*/ uint16(xSetOp), uint16(BTR), + /*6342*/ uint16(xReadSlashR), + /*6343*/ uint16(xArgRM64), + /*6344*/ uint16(xArgR64), + /*6345*/ uint16(xMatch), + /*6346*/ uint16(xCondIs64), 6349, 6365, + /*6349*/ uint16(xCondDataSize), 6353, 6359, 0, + /*6353*/ uint16(xSetOp), uint16(LFS), + /*6355*/ uint16(xReadSlashR), + /*6356*/ uint16(xArgR16), + /*6357*/ uint16(xArgM16colon16), + /*6358*/ uint16(xMatch), + /*6359*/ uint16(xSetOp), uint16(LFS), + /*6361*/ uint16(xReadSlashR), + /*6362*/ uint16(xArgR32), + /*6363*/ uint16(xArgM16colon32), + /*6364*/ uint16(xMatch), + /*6365*/ uint16(xCondDataSize), 6353, 6359, 6369, + /*6369*/ uint16(xSetOp), uint16(LFS), + /*6371*/ uint16(xReadSlashR), + /*6372*/ uint16(xArgR64), + /*6373*/ uint16(xArgM16colon64), + /*6374*/ uint16(xMatch), + /*6375*/ uint16(xCondIs64), 6378, 6394, + /*6378*/ uint16(xCondDataSize), 6382, 6388, 0, + /*6382*/ uint16(xSetOp), uint16(LGS), + /*6384*/ uint16(xReadSlashR), + /*6385*/ uint16(xArgR16), + /*6386*/ uint16(xArgM16colon16), + /*6387*/ uint16(xMatch), + /*6388*/ uint16(xSetOp), uint16(LGS), + /*6390*/ uint16(xReadSlashR), + /*6391*/ uint16(xArgR32), + /*6392*/ uint16(xArgM16colon32), + /*6393*/ uint16(xMatch), + /*6394*/ uint16(xCondDataSize), 6382, 6388, 6398, + /*6398*/ uint16(xSetOp), uint16(LGS), + /*6400*/ uint16(xReadSlashR), + /*6401*/ uint16(xArgR64), + /*6402*/ uint16(xArgM16colon64), + /*6403*/ uint16(xMatch), + /*6404*/ uint16(xCondIs64), 6407, 6423, + /*6407*/ uint16(xCondDataSize), 6411, 6417, 0, + /*6411*/ uint16(xSetOp), uint16(MOVZX), + /*6413*/ uint16(xReadSlashR), + /*6414*/ uint16(xArgR16), + /*6415*/ uint16(xArgRM8), + /*6416*/ uint16(xMatch), + /*6417*/ uint16(xSetOp), uint16(MOVZX), + /*6419*/ uint16(xReadSlashR), + /*6420*/ uint16(xArgR32), + /*6421*/ uint16(xArgRM8), + /*6422*/ uint16(xMatch), + /*6423*/ uint16(xCondDataSize), 6411, 6417, 6427, + /*6427*/ uint16(xSetOp), uint16(MOVZX), + /*6429*/ uint16(xReadSlashR), + /*6430*/ uint16(xArgR64), + /*6431*/ uint16(xArgRM8), + /*6432*/ uint16(xMatch), + /*6433*/ uint16(xCondIs64), 6436, 6452, + /*6436*/ uint16(xCondDataSize), 6440, 6446, 0, + /*6440*/ uint16(xSetOp), uint16(MOVZX), + /*6442*/ uint16(xReadSlashR), + /*6443*/ uint16(xArgR16), + /*6444*/ uint16(xArgRM16), + /*6445*/ uint16(xMatch), + /*6446*/ uint16(xSetOp), uint16(MOVZX), + /*6448*/ uint16(xReadSlashR), + /*6449*/ uint16(xArgR32), + /*6450*/ uint16(xArgRM16), + /*6451*/ uint16(xMatch), + /*6452*/ uint16(xCondDataSize), 6440, 6446, 6456, + /*6456*/ uint16(xSetOp), uint16(MOVZX), + /*6458*/ uint16(xReadSlashR), + /*6459*/ uint16(xArgR64), + /*6460*/ uint16(xArgRM16), + /*6461*/ uint16(xMatch), + /*6462*/ uint16(xCondIs64), 6465, 6485, + /*6465*/ uint16(xCondPrefix), 1, + 0xF3, 6469, + /*6469*/ uint16(xCondDataSize), 6473, 6479, 0, + /*6473*/ uint16(xSetOp), uint16(POPCNT), + /*6475*/ uint16(xReadSlashR), + /*6476*/ uint16(xArgR16), + /*6477*/ uint16(xArgRM16), + /*6478*/ uint16(xMatch), + /*6479*/ uint16(xSetOp), uint16(POPCNT), + /*6481*/ uint16(xReadSlashR), + /*6482*/ uint16(xArgR32), + /*6483*/ uint16(xArgRM32), + /*6484*/ uint16(xMatch), + /*6485*/ uint16(xCondPrefix), 1, + 0xF3, 6489, + /*6489*/ uint16(xCondDataSize), 6473, 6479, 6493, + /*6493*/ uint16(xSetOp), uint16(POPCNT), + /*6495*/ uint16(xReadSlashR), + /*6496*/ uint16(xArgR64), + /*6497*/ uint16(xArgRM64), + /*6498*/ uint16(xMatch), + /*6499*/ uint16(xSetOp), uint16(UD1), + /*6501*/ uint16(xMatch), + /*6502*/ uint16(xCondSlashR), + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 6511, // 4 + 6540, // 5 + 6569, // 6 + 6598, // 7 + /*6511*/ uint16(xCondIs64), 6514, 6530, + /*6514*/ uint16(xCondDataSize), 6518, 6524, 0, + /*6518*/ uint16(xSetOp), uint16(BT), + /*6520*/ uint16(xReadIb), + /*6521*/ uint16(xArgRM16), + /*6522*/ uint16(xArgImm8u), + /*6523*/ uint16(xMatch), + /*6524*/ uint16(xSetOp), uint16(BT), + /*6526*/ uint16(xReadIb), + /*6527*/ uint16(xArgRM32), + /*6528*/ uint16(xArgImm8u), + /*6529*/ uint16(xMatch), + /*6530*/ uint16(xCondDataSize), 6518, 6524, 6534, + /*6534*/ uint16(xSetOp), uint16(BT), + /*6536*/ uint16(xReadIb), + /*6537*/ uint16(xArgRM64), + /*6538*/ uint16(xArgImm8u), + /*6539*/ uint16(xMatch), + /*6540*/ uint16(xCondIs64), 6543, 6559, + /*6543*/ uint16(xCondDataSize), 6547, 6553, 0, + /*6547*/ uint16(xSetOp), uint16(BTS), + /*6549*/ uint16(xReadIb), + /*6550*/ uint16(xArgRM16), + /*6551*/ uint16(xArgImm8u), + /*6552*/ uint16(xMatch), + /*6553*/ uint16(xSetOp), uint16(BTS), + /*6555*/ uint16(xReadIb), + /*6556*/ uint16(xArgRM32), + /*6557*/ uint16(xArgImm8u), + /*6558*/ uint16(xMatch), + /*6559*/ uint16(xCondDataSize), 6547, 6553, 6563, + /*6563*/ uint16(xSetOp), uint16(BTS), + /*6565*/ uint16(xReadIb), + /*6566*/ uint16(xArgRM64), + /*6567*/ uint16(xArgImm8u), + /*6568*/ uint16(xMatch), + /*6569*/ uint16(xCondIs64), 6572, 6588, + /*6572*/ uint16(xCondDataSize), 6576, 6582, 0, + /*6576*/ uint16(xSetOp), uint16(BTR), + /*6578*/ uint16(xReadIb), + /*6579*/ uint16(xArgRM16), + /*6580*/ uint16(xArgImm8u), + /*6581*/ uint16(xMatch), + /*6582*/ uint16(xSetOp), uint16(BTR), + /*6584*/ uint16(xReadIb), + /*6585*/ uint16(xArgRM32), + /*6586*/ uint16(xArgImm8u), + /*6587*/ uint16(xMatch), + /*6588*/ uint16(xCondDataSize), 6576, 6582, 6592, + /*6592*/ uint16(xSetOp), uint16(BTR), + /*6594*/ uint16(xReadIb), + /*6595*/ uint16(xArgRM64), + /*6596*/ uint16(xArgImm8u), + /*6597*/ uint16(xMatch), + /*6598*/ uint16(xCondIs64), 6601, 6617, + /*6601*/ uint16(xCondDataSize), 6605, 6611, 0, + /*6605*/ uint16(xSetOp), uint16(BTC), + /*6607*/ uint16(xReadIb), + /*6608*/ uint16(xArgRM16), + /*6609*/ uint16(xArgImm8u), + /*6610*/ uint16(xMatch), + /*6611*/ uint16(xSetOp), uint16(BTC), + /*6613*/ uint16(xReadIb), + /*6614*/ uint16(xArgRM32), + /*6615*/ uint16(xArgImm8u), + /*6616*/ uint16(xMatch), + /*6617*/ uint16(xCondDataSize), 6605, 6611, 6621, + /*6621*/ uint16(xSetOp), uint16(BTC), + /*6623*/ uint16(xReadIb), + /*6624*/ uint16(xArgRM64), + /*6625*/ uint16(xArgImm8u), + /*6626*/ uint16(xMatch), + /*6627*/ uint16(xCondIs64), 6630, 6646, + /*6630*/ uint16(xCondDataSize), 6634, 6640, 0, + /*6634*/ uint16(xSetOp), uint16(BTC), + /*6636*/ uint16(xReadSlashR), + /*6637*/ uint16(xArgRM16), + /*6638*/ uint16(xArgR16), + /*6639*/ uint16(xMatch), + /*6640*/ uint16(xSetOp), uint16(BTC), + /*6642*/ uint16(xReadSlashR), + /*6643*/ uint16(xArgRM32), + /*6644*/ uint16(xArgR32), + /*6645*/ uint16(xMatch), + /*6646*/ uint16(xCondDataSize), 6634, 6640, 6650, + /*6650*/ uint16(xSetOp), uint16(BTC), + /*6652*/ uint16(xReadSlashR), + /*6653*/ uint16(xArgRM64), + /*6654*/ uint16(xArgR64), + /*6655*/ uint16(xMatch), + /*6656*/ uint16(xCondIs64), 6659, 6697, + /*6659*/ uint16(xCondPrefix), 2, + 0xF3, 6681, + 0x0, 6665, + /*6665*/ uint16(xCondDataSize), 6669, 6675, 0, + /*6669*/ uint16(xSetOp), uint16(BSF), + /*6671*/ uint16(xReadSlashR), + /*6672*/ uint16(xArgR16), + /*6673*/ uint16(xArgRM16), + /*6674*/ uint16(xMatch), + /*6675*/ uint16(xSetOp), uint16(BSF), + /*6677*/ uint16(xReadSlashR), + /*6678*/ uint16(xArgR32), + /*6679*/ uint16(xArgRM32), + /*6680*/ uint16(xMatch), + /*6681*/ uint16(xCondDataSize), 6685, 6691, 0, + /*6685*/ uint16(xSetOp), uint16(TZCNT), + /*6687*/ uint16(xReadSlashR), + /*6688*/ uint16(xArgR16), + /*6689*/ uint16(xArgRM16), + /*6690*/ uint16(xMatch), + /*6691*/ uint16(xSetOp), uint16(TZCNT), + /*6693*/ uint16(xReadSlashR), + /*6694*/ uint16(xArgR32), + /*6695*/ uint16(xArgRM32), + /*6696*/ uint16(xMatch), + /*6697*/ uint16(xCondPrefix), 2, + 0xF3, 6713, + 0x0, 6703, + /*6703*/ uint16(xCondDataSize), 6669, 6675, 6707, + /*6707*/ uint16(xSetOp), uint16(BSF), + /*6709*/ uint16(xReadSlashR), + /*6710*/ uint16(xArgR64), + /*6711*/ uint16(xArgRM64), + /*6712*/ uint16(xMatch), + /*6713*/ uint16(xCondDataSize), 6685, 6691, 6717, + /*6717*/ uint16(xSetOp), uint16(TZCNT), + /*6719*/ uint16(xReadSlashR), + /*6720*/ uint16(xArgR64), + /*6721*/ uint16(xArgRM64), + /*6722*/ uint16(xMatch), + /*6723*/ uint16(xCondIs64), 6726, 6764, + /*6726*/ uint16(xCondPrefix), 2, + 0xF3, 6748, + 0x0, 6732, + /*6732*/ uint16(xCondDataSize), 6736, 6742, 0, + /*6736*/ uint16(xSetOp), uint16(BSR), + /*6738*/ uint16(xReadSlashR), + /*6739*/ uint16(xArgR16), + /*6740*/ uint16(xArgRM16), + /*6741*/ uint16(xMatch), + /*6742*/ uint16(xSetOp), uint16(BSR), + /*6744*/ uint16(xReadSlashR), + /*6745*/ uint16(xArgR32), + /*6746*/ uint16(xArgRM32), + /*6747*/ uint16(xMatch), + /*6748*/ uint16(xCondDataSize), 6752, 6758, 0, + /*6752*/ uint16(xSetOp), uint16(LZCNT), + /*6754*/ uint16(xReadSlashR), + /*6755*/ uint16(xArgR16), + /*6756*/ uint16(xArgRM16), + /*6757*/ uint16(xMatch), + /*6758*/ uint16(xSetOp), uint16(LZCNT), + /*6760*/ uint16(xReadSlashR), + /*6761*/ uint16(xArgR32), + /*6762*/ uint16(xArgRM32), + /*6763*/ uint16(xMatch), + /*6764*/ uint16(xCondPrefix), 2, + 0xF3, 6780, + 0x0, 6770, + /*6770*/ uint16(xCondDataSize), 6736, 6742, 6774, + /*6774*/ uint16(xSetOp), uint16(BSR), + /*6776*/ uint16(xReadSlashR), + /*6777*/ uint16(xArgR64), + /*6778*/ uint16(xArgRM64), + /*6779*/ uint16(xMatch), + /*6780*/ uint16(xCondDataSize), 6752, 6758, 6784, + /*6784*/ uint16(xSetOp), uint16(LZCNT), + /*6786*/ uint16(xReadSlashR), + /*6787*/ uint16(xArgR64), + /*6788*/ uint16(xArgRM64), + /*6789*/ uint16(xMatch), + /*6790*/ uint16(xCondIs64), 6793, 6809, + /*6793*/ uint16(xCondDataSize), 6797, 6803, 0, + /*6797*/ uint16(xSetOp), uint16(MOVSX), + /*6799*/ uint16(xReadSlashR), + /*6800*/ uint16(xArgR16), + /*6801*/ uint16(xArgRM8), + /*6802*/ uint16(xMatch), + /*6803*/ uint16(xSetOp), uint16(MOVSX), + /*6805*/ uint16(xReadSlashR), + /*6806*/ uint16(xArgR32), + /*6807*/ uint16(xArgRM8), + /*6808*/ uint16(xMatch), + /*6809*/ uint16(xCondDataSize), 6797, 6803, 6813, + /*6813*/ uint16(xSetOp), uint16(MOVSX), + /*6815*/ uint16(xReadSlashR), + /*6816*/ uint16(xArgR64), + /*6817*/ uint16(xArgRM8), + /*6818*/ uint16(xMatch), + /*6819*/ uint16(xCondIs64), 6822, 6838, + /*6822*/ uint16(xCondDataSize), 6826, 6832, 0, + /*6826*/ uint16(xSetOp), uint16(MOVSX), + /*6828*/ uint16(xReadSlashR), + /*6829*/ uint16(xArgR16), + /*6830*/ uint16(xArgRM16), + /*6831*/ uint16(xMatch), + /*6832*/ uint16(xSetOp), uint16(MOVSX), + /*6834*/ uint16(xReadSlashR), + /*6835*/ uint16(xArgR32), + /*6836*/ uint16(xArgRM16), + /*6837*/ uint16(xMatch), + /*6838*/ uint16(xCondDataSize), 6826, 6832, 6842, + /*6842*/ uint16(xSetOp), uint16(MOVSX), + /*6844*/ uint16(xReadSlashR), + /*6845*/ uint16(xArgR64), + /*6846*/ uint16(xArgRM16), + /*6847*/ uint16(xMatch), + /*6848*/ uint16(xSetOp), uint16(XADD), + /*6850*/ uint16(xReadSlashR), + /*6851*/ uint16(xArgRM8), + /*6852*/ uint16(xArgR8), + /*6853*/ uint16(xMatch), + /*6854*/ uint16(xCondIs64), 6857, 6873, + /*6857*/ uint16(xCondDataSize), 6861, 6867, 0, + /*6861*/ uint16(xSetOp), uint16(XADD), + /*6863*/ uint16(xReadSlashR), + /*6864*/ uint16(xArgRM16), + /*6865*/ uint16(xArgR16), + /*6866*/ uint16(xMatch), + /*6867*/ uint16(xSetOp), uint16(XADD), + /*6869*/ uint16(xReadSlashR), + /*6870*/ uint16(xArgRM32), + /*6871*/ uint16(xArgR32), + /*6872*/ uint16(xMatch), + /*6873*/ uint16(xCondDataSize), 6861, 6867, 6877, + /*6877*/ uint16(xSetOp), uint16(XADD), + /*6879*/ uint16(xReadSlashR), + /*6880*/ uint16(xArgRM64), + /*6881*/ uint16(xArgR64), + /*6882*/ uint16(xMatch), + /*6883*/ uint16(xCondPrefix), 4, + 0xF3, 6917, + 0xF2, 6909, + 0x66, 6901, + 0x0, 6893, + /*6893*/ uint16(xSetOp), uint16(CMPPS), + /*6895*/ uint16(xReadSlashR), + /*6896*/ uint16(xReadIb), + /*6897*/ uint16(xArgXmm1), + /*6898*/ uint16(xArgXmm2M128), + /*6899*/ uint16(xArgImm8u), + /*6900*/ uint16(xMatch), + /*6901*/ uint16(xSetOp), uint16(CMPPD), + /*6903*/ uint16(xReadSlashR), + /*6904*/ uint16(xReadIb), + /*6905*/ uint16(xArgXmm1), + /*6906*/ uint16(xArgXmm2M128), + /*6907*/ uint16(xArgImm8u), + /*6908*/ uint16(xMatch), + /*6909*/ uint16(xSetOp), uint16(CMPSD_XMM), + /*6911*/ uint16(xReadSlashR), + /*6912*/ uint16(xReadIb), + /*6913*/ uint16(xArgXmm1), + /*6914*/ uint16(xArgXmm2M64), + /*6915*/ uint16(xArgImm8u), + /*6916*/ uint16(xMatch), + /*6917*/ uint16(xSetOp), uint16(CMPSS), + /*6919*/ uint16(xReadSlashR), + /*6920*/ uint16(xReadIb), + /*6921*/ uint16(xArgXmm1), + /*6922*/ uint16(xArgXmm2M32), + /*6923*/ uint16(xArgImm8u), + /*6924*/ uint16(xMatch), + /*6925*/ uint16(xCondIs64), 6928, 6944, + /*6928*/ uint16(xCondDataSize), 6932, 6938, 0, + /*6932*/ uint16(xSetOp), uint16(MOVNTI), + /*6934*/ uint16(xReadSlashR), + /*6935*/ uint16(xArgM32), + /*6936*/ uint16(xArgR32), + /*6937*/ uint16(xMatch), + /*6938*/ uint16(xSetOp), uint16(MOVNTI), + /*6940*/ uint16(xReadSlashR), + /*6941*/ uint16(xArgM32), + /*6942*/ uint16(xArgR32), + /*6943*/ uint16(xMatch), + /*6944*/ uint16(xCondDataSize), 6932, 6938, 6948, + /*6948*/ uint16(xSetOp), uint16(MOVNTI), + /*6950*/ uint16(xReadSlashR), + /*6951*/ uint16(xArgM64), + /*6952*/ uint16(xArgR64), + /*6953*/ uint16(xMatch), + /*6954*/ uint16(xCondPrefix), 2, + 0x66, 6968, + 0x0, 6960, + /*6960*/ uint16(xSetOp), uint16(PINSRW), + /*6962*/ uint16(xReadSlashR), + /*6963*/ uint16(xReadIb), + /*6964*/ uint16(xArgMm), + /*6965*/ uint16(xArgR32M16), + /*6966*/ uint16(xArgImm8u), + /*6967*/ uint16(xMatch), + /*6968*/ uint16(xSetOp), uint16(PINSRW), + /*6970*/ uint16(xReadSlashR), + /*6971*/ uint16(xReadIb), + /*6972*/ uint16(xArgXmm), + /*6973*/ uint16(xArgR32M16), + /*6974*/ uint16(xArgImm8u), + /*6975*/ uint16(xMatch), + /*6976*/ uint16(xCondPrefix), 2, + 0x66, 6990, + 0x0, 6982, + /*6982*/ uint16(xSetOp), uint16(PEXTRW), + /*6984*/ uint16(xReadSlashR), + /*6985*/ uint16(xReadIb), + /*6986*/ uint16(xArgR32), + /*6987*/ uint16(xArgMm2), + /*6988*/ uint16(xArgImm8u), + /*6989*/ uint16(xMatch), + /*6990*/ uint16(xSetOp), uint16(PEXTRW), + /*6992*/ uint16(xReadSlashR), + /*6993*/ uint16(xReadIb), + /*6994*/ uint16(xArgR32), + /*6995*/ uint16(xArgXmm2), + /*6996*/ uint16(xArgImm8u), + /*6997*/ uint16(xMatch), + /*6998*/ uint16(xCondPrefix), 2, + 0x66, 7012, + 0x0, 7004, + /*7004*/ uint16(xSetOp), uint16(SHUFPS), + /*7006*/ uint16(xReadSlashR), + /*7007*/ uint16(xReadIb), + /*7008*/ uint16(xArgXmm1), + /*7009*/ uint16(xArgXmm2M128), + /*7010*/ uint16(xArgImm8u), + /*7011*/ uint16(xMatch), + /*7012*/ uint16(xSetOp), uint16(SHUFPD), + /*7014*/ uint16(xReadSlashR), + /*7015*/ uint16(xReadIb), + /*7016*/ uint16(xArgXmm1), + /*7017*/ uint16(xArgXmm2M128), + /*7018*/ uint16(xArgImm8u), + /*7019*/ uint16(xMatch), + /*7020*/ uint16(xCondSlashR), + 0, // 0 + 7029, // 1 + 0, // 2 + 7052, // 3 + 7075, // 4 + 7098, // 5 + 7121, // 6 + 0, // 7 + /*7029*/ uint16(xCondIs64), 7032, 7044, + /*7032*/ uint16(xCondDataSize), 7036, 7040, 0, + /*7036*/ uint16(xSetOp), uint16(CMPXCHG8B), + /*7038*/ uint16(xArgM64), + /*7039*/ uint16(xMatch), + /*7040*/ uint16(xSetOp), uint16(CMPXCHG8B), + /*7042*/ uint16(xArgM64), + /*7043*/ uint16(xMatch), + /*7044*/ uint16(xCondDataSize), 7036, 7040, 7048, + /*7048*/ uint16(xSetOp), uint16(CMPXCHG16B), + /*7050*/ uint16(xArgM128), + /*7051*/ uint16(xMatch), + /*7052*/ uint16(xCondIs64), 7055, 7067, + /*7055*/ uint16(xCondDataSize), 7059, 7063, 0, + /*7059*/ uint16(xSetOp), uint16(XRSTORS), + /*7061*/ uint16(xArgMem), + /*7062*/ uint16(xMatch), + /*7063*/ uint16(xSetOp), uint16(XRSTORS), + /*7065*/ uint16(xArgMem), + /*7066*/ uint16(xMatch), + /*7067*/ uint16(xCondDataSize), 7059, 7063, 7071, + /*7071*/ uint16(xSetOp), uint16(XRSTORS64), + /*7073*/ uint16(xArgMem), + /*7074*/ uint16(xMatch), + /*7075*/ uint16(xCondIs64), 7078, 7090, + /*7078*/ uint16(xCondDataSize), 7082, 7086, 0, + /*7082*/ uint16(xSetOp), uint16(XSAVEC), + /*7084*/ uint16(xArgMem), + /*7085*/ uint16(xMatch), + /*7086*/ uint16(xSetOp), uint16(XSAVEC), + /*7088*/ uint16(xArgMem), + /*7089*/ uint16(xMatch), + /*7090*/ uint16(xCondDataSize), 7082, 7086, 7094, + /*7094*/ uint16(xSetOp), uint16(XSAVEC64), + /*7096*/ uint16(xArgMem), + /*7097*/ uint16(xMatch), + /*7098*/ uint16(xCondIs64), 7101, 7113, + /*7101*/ uint16(xCondDataSize), 7105, 7109, 0, + /*7105*/ uint16(xSetOp), uint16(XSAVES), + /*7107*/ uint16(xArgMem), + /*7108*/ uint16(xMatch), + /*7109*/ uint16(xSetOp), uint16(XSAVES), + /*7111*/ uint16(xArgMem), + /*7112*/ uint16(xMatch), + /*7113*/ uint16(xCondDataSize), 7105, 7109, 7117, + /*7117*/ uint16(xSetOp), uint16(XSAVES64), + /*7119*/ uint16(xArgMem), + /*7120*/ uint16(xMatch), + /*7121*/ uint16(xCondIs64), 7124, 7142, + /*7124*/ uint16(xCondDataSize), 7128, 7135, 0, + /*7128*/ uint16(xCondIsMem), 7131, 0, + /*7131*/ uint16(xSetOp), uint16(RDRAND), + /*7133*/ uint16(xArgRmf16), + /*7134*/ uint16(xMatch), + /*7135*/ uint16(xCondIsMem), 7138, 0, + /*7138*/ uint16(xSetOp), uint16(RDRAND), + /*7140*/ uint16(xArgRmf32), + /*7141*/ uint16(xMatch), + /*7142*/ uint16(xCondDataSize), 7128, 7135, 7146, + /*7146*/ uint16(xSetOp), uint16(RDRAND), + /*7148*/ uint16(xMatch), + /*7149*/ uint16(xCondIs64), 7152, 7164, + /*7152*/ uint16(xCondDataSize), 7156, 7160, 0, + /*7156*/ uint16(xSetOp), uint16(BSWAP), + /*7158*/ uint16(xArgR16op), + /*7159*/ uint16(xMatch), + /*7160*/ uint16(xSetOp), uint16(BSWAP), + /*7162*/ uint16(xArgR32op), + /*7163*/ uint16(xMatch), + /*7164*/ uint16(xCondDataSize), 7156, 7160, 7168, + /*7168*/ uint16(xSetOp), uint16(BSWAP), + /*7170*/ uint16(xArgR64op), + /*7171*/ uint16(xMatch), + /*7172*/ uint16(xCondPrefix), 2, + 0xF2, 7184, + 0x66, 7178, + /*7178*/ uint16(xSetOp), uint16(ADDSUBPD), + /*7180*/ uint16(xReadSlashR), + /*7181*/ uint16(xArgXmm1), + /*7182*/ uint16(xArgXmm2M128), + /*7183*/ uint16(xMatch), + /*7184*/ uint16(xSetOp), uint16(ADDSUBPS), + /*7186*/ uint16(xReadSlashR), + /*7187*/ uint16(xArgXmm1), + /*7188*/ uint16(xArgXmm2M128), + /*7189*/ uint16(xMatch), + /*7190*/ uint16(xCondPrefix), 2, + 0x66, 7202, + 0x0, 7196, + /*7196*/ uint16(xSetOp), uint16(PSRLW), + /*7198*/ uint16(xReadSlashR), + /*7199*/ uint16(xArgMm), + /*7200*/ uint16(xArgMmM64), + /*7201*/ uint16(xMatch), + /*7202*/ uint16(xSetOp), uint16(PSRLW), + /*7204*/ uint16(xReadSlashR), + /*7205*/ uint16(xArgXmm1), + /*7206*/ uint16(xArgXmm2M128), + /*7207*/ uint16(xMatch), + /*7208*/ uint16(xCondPrefix), 2, + 0x66, 7220, + 0x0, 7214, + /*7214*/ uint16(xSetOp), uint16(PSRLD), + /*7216*/ uint16(xReadSlashR), + /*7217*/ uint16(xArgMm), + /*7218*/ uint16(xArgMmM64), + /*7219*/ uint16(xMatch), + /*7220*/ uint16(xSetOp), uint16(PSRLD), + /*7222*/ uint16(xReadSlashR), + /*7223*/ uint16(xArgXmm1), + /*7224*/ uint16(xArgXmm2M128), + /*7225*/ uint16(xMatch), + /*7226*/ uint16(xCondPrefix), 2, + 0x66, 7238, + 0x0, 7232, + /*7232*/ uint16(xSetOp), uint16(PSRLQ), + /*7234*/ uint16(xReadSlashR), + /*7235*/ uint16(xArgMm), + /*7236*/ uint16(xArgMmM64), + /*7237*/ uint16(xMatch), + /*7238*/ uint16(xSetOp), uint16(PSRLQ), + /*7240*/ uint16(xReadSlashR), + /*7241*/ uint16(xArgXmm1), + /*7242*/ uint16(xArgXmm2M128), + /*7243*/ uint16(xMatch), + /*7244*/ uint16(xCondPrefix), 2, + 0x66, 7256, + 0x0, 7250, + /*7250*/ uint16(xSetOp), uint16(PADDQ), + /*7252*/ uint16(xReadSlashR), + /*7253*/ uint16(xArgMm1), + /*7254*/ uint16(xArgMm2M64), + /*7255*/ uint16(xMatch), + /*7256*/ uint16(xSetOp), uint16(PADDQ), + /*7258*/ uint16(xReadSlashR), + /*7259*/ uint16(xArgXmm1), + /*7260*/ uint16(xArgXmm2M128), + /*7261*/ uint16(xMatch), + /*7262*/ uint16(xCondPrefix), 2, + 0x66, 7274, + 0x0, 7268, + /*7268*/ uint16(xSetOp), uint16(PMULLW), + /*7270*/ uint16(xReadSlashR), + /*7271*/ uint16(xArgMm), + /*7272*/ uint16(xArgMmM64), + /*7273*/ uint16(xMatch), + /*7274*/ uint16(xSetOp), uint16(PMULLW), + /*7276*/ uint16(xReadSlashR), + /*7277*/ uint16(xArgXmm1), + /*7278*/ uint16(xArgXmm2M128), + /*7279*/ uint16(xMatch), + /*7280*/ uint16(xCondPrefix), 3, + 0xF3, 7300, + 0xF2, 7294, + 0x66, 7288, + /*7288*/ uint16(xSetOp), uint16(MOVQ), + /*7290*/ uint16(xReadSlashR), + /*7291*/ uint16(xArgXmm2M64), + /*7292*/ uint16(xArgXmm1), + /*7293*/ uint16(xMatch), + /*7294*/ uint16(xSetOp), uint16(MOVDQ2Q), + /*7296*/ uint16(xReadSlashR), + /*7297*/ uint16(xArgMm), + /*7298*/ uint16(xArgXmm2), + /*7299*/ uint16(xMatch), + /*7300*/ uint16(xSetOp), uint16(MOVQ2DQ), + /*7302*/ uint16(xReadSlashR), + /*7303*/ uint16(xArgXmm1), + /*7304*/ uint16(xArgMm2), + /*7305*/ uint16(xMatch), + /*7306*/ uint16(xCondPrefix), 2, + 0x66, 7318, + 0x0, 7312, + /*7312*/ uint16(xSetOp), uint16(PMOVMSKB), + /*7314*/ uint16(xReadSlashR), + /*7315*/ uint16(xArgR32), + /*7316*/ uint16(xArgMm2), + /*7317*/ uint16(xMatch), + /*7318*/ uint16(xSetOp), uint16(PMOVMSKB), + /*7320*/ uint16(xReadSlashR), + /*7321*/ uint16(xArgR32), + /*7322*/ uint16(xArgXmm2), + /*7323*/ uint16(xMatch), + /*7324*/ uint16(xCondPrefix), 2, + 0x66, 7336, + 0x0, 7330, + /*7330*/ uint16(xSetOp), uint16(PSUBUSB), + /*7332*/ uint16(xReadSlashR), + /*7333*/ uint16(xArgMm), + /*7334*/ uint16(xArgMmM64), + /*7335*/ uint16(xMatch), + /*7336*/ uint16(xSetOp), uint16(PSUBUSB), + /*7338*/ uint16(xReadSlashR), + /*7339*/ uint16(xArgXmm1), + /*7340*/ uint16(xArgXmm2M128), + /*7341*/ uint16(xMatch), + /*7342*/ uint16(xCondPrefix), 2, + 0x66, 7354, + 0x0, 7348, + /*7348*/ uint16(xSetOp), uint16(PSUBUSW), + /*7350*/ uint16(xReadSlashR), + /*7351*/ uint16(xArgMm), + /*7352*/ uint16(xArgMmM64), + /*7353*/ uint16(xMatch), + /*7354*/ uint16(xSetOp), uint16(PSUBUSW), + /*7356*/ uint16(xReadSlashR), + /*7357*/ uint16(xArgXmm1), + /*7358*/ uint16(xArgXmm2M128), + /*7359*/ uint16(xMatch), + /*7360*/ uint16(xCondPrefix), 2, + 0x66, 7372, + 0x0, 7366, + /*7366*/ uint16(xSetOp), uint16(PMINUB), + /*7368*/ uint16(xReadSlashR), + /*7369*/ uint16(xArgMm1), + /*7370*/ uint16(xArgMm2M64), + /*7371*/ uint16(xMatch), + /*7372*/ uint16(xSetOp), uint16(PMINUB), + /*7374*/ uint16(xReadSlashR), + /*7375*/ uint16(xArgXmm1), + /*7376*/ uint16(xArgXmm2M128), + /*7377*/ uint16(xMatch), + /*7378*/ uint16(xCondPrefix), 2, + 0x66, 7390, + 0x0, 7384, + /*7384*/ uint16(xSetOp), uint16(PAND), + /*7386*/ uint16(xReadSlashR), + /*7387*/ uint16(xArgMm), + /*7388*/ uint16(xArgMmM64), + /*7389*/ uint16(xMatch), + /*7390*/ uint16(xSetOp), uint16(PAND), + /*7392*/ uint16(xReadSlashR), + /*7393*/ uint16(xArgXmm1), + /*7394*/ uint16(xArgXmm2M128), + /*7395*/ uint16(xMatch), + /*7396*/ uint16(xCondPrefix), 2, + 0x66, 7408, + 0x0, 7402, + /*7402*/ uint16(xSetOp), uint16(PADDUSB), + /*7404*/ uint16(xReadSlashR), + /*7405*/ uint16(xArgMm), + /*7406*/ uint16(xArgMmM64), + /*7407*/ uint16(xMatch), + /*7408*/ uint16(xSetOp), uint16(PADDUSB), + /*7410*/ uint16(xReadSlashR), + /*7411*/ uint16(xArgXmm1), + /*7412*/ uint16(xArgXmm2M128), + /*7413*/ uint16(xMatch), + /*7414*/ uint16(xCondPrefix), 2, + 0x66, 7426, + 0x0, 7420, + /*7420*/ uint16(xSetOp), uint16(PADDUSW), + /*7422*/ uint16(xReadSlashR), + /*7423*/ uint16(xArgMm), + /*7424*/ uint16(xArgMmM64), + /*7425*/ uint16(xMatch), + /*7426*/ uint16(xSetOp), uint16(PADDUSW), + /*7428*/ uint16(xReadSlashR), + /*7429*/ uint16(xArgXmm1), + /*7430*/ uint16(xArgXmm2M128), + /*7431*/ uint16(xMatch), + /*7432*/ uint16(xCondPrefix), 2, + 0x66, 7444, + 0x0, 7438, + /*7438*/ uint16(xSetOp), uint16(PMAXUB), + /*7440*/ uint16(xReadSlashR), + /*7441*/ uint16(xArgMm1), + /*7442*/ uint16(xArgMm2M64), + /*7443*/ uint16(xMatch), + /*7444*/ uint16(xSetOp), uint16(PMAXUB), + /*7446*/ uint16(xReadSlashR), + /*7447*/ uint16(xArgXmm1), + /*7448*/ uint16(xArgXmm2M128), + /*7449*/ uint16(xMatch), + /*7450*/ uint16(xCondPrefix), 2, + 0x66, 7462, + 0x0, 7456, + /*7456*/ uint16(xSetOp), uint16(PANDN), + /*7458*/ uint16(xReadSlashR), + /*7459*/ uint16(xArgMm), + /*7460*/ uint16(xArgMmM64), + /*7461*/ uint16(xMatch), + /*7462*/ uint16(xSetOp), uint16(PANDN), + /*7464*/ uint16(xReadSlashR), + /*7465*/ uint16(xArgXmm1), + /*7466*/ uint16(xArgXmm2M128), + /*7467*/ uint16(xMatch), + /*7468*/ uint16(xCondPrefix), 2, + 0x66, 7480, + 0x0, 7474, + /*7474*/ uint16(xSetOp), uint16(PAVGB), + /*7476*/ uint16(xReadSlashR), + /*7477*/ uint16(xArgMm1), + /*7478*/ uint16(xArgMm2M64), + /*7479*/ uint16(xMatch), + /*7480*/ uint16(xSetOp), uint16(PAVGB), + /*7482*/ uint16(xReadSlashR), + /*7483*/ uint16(xArgXmm1), + /*7484*/ uint16(xArgXmm2M128), + /*7485*/ uint16(xMatch), + /*7486*/ uint16(xCondPrefix), 2, + 0x66, 7498, + 0x0, 7492, + /*7492*/ uint16(xSetOp), uint16(PSRAW), + /*7494*/ uint16(xReadSlashR), + /*7495*/ uint16(xArgMm), + /*7496*/ uint16(xArgMmM64), + /*7497*/ uint16(xMatch), + /*7498*/ uint16(xSetOp), uint16(PSRAW), + /*7500*/ uint16(xReadSlashR), + /*7501*/ uint16(xArgXmm1), + /*7502*/ uint16(xArgXmm2M128), + /*7503*/ uint16(xMatch), + /*7504*/ uint16(xCondPrefix), 2, + 0x66, 7516, + 0x0, 7510, + /*7510*/ uint16(xSetOp), uint16(PSRAD), + /*7512*/ uint16(xReadSlashR), + /*7513*/ uint16(xArgMm), + /*7514*/ uint16(xArgMmM64), + /*7515*/ uint16(xMatch), + /*7516*/ uint16(xSetOp), uint16(PSRAD), + /*7518*/ uint16(xReadSlashR), + /*7519*/ uint16(xArgXmm1), + /*7520*/ uint16(xArgXmm2M128), + /*7521*/ uint16(xMatch), + /*7522*/ uint16(xCondPrefix), 2, + 0x66, 7534, + 0x0, 7528, + /*7528*/ uint16(xSetOp), uint16(PAVGW), + /*7530*/ uint16(xReadSlashR), + /*7531*/ uint16(xArgMm1), + /*7532*/ uint16(xArgMm2M64), + /*7533*/ uint16(xMatch), + /*7534*/ uint16(xSetOp), uint16(PAVGW), + /*7536*/ uint16(xReadSlashR), + /*7537*/ uint16(xArgXmm1), + /*7538*/ uint16(xArgXmm2M128), + /*7539*/ uint16(xMatch), + /*7540*/ uint16(xCondPrefix), 2, + 0x66, 7552, + 0x0, 7546, + /*7546*/ uint16(xSetOp), uint16(PMULHUW), + /*7548*/ uint16(xReadSlashR), + /*7549*/ uint16(xArgMm1), + /*7550*/ uint16(xArgMm2M64), + /*7551*/ uint16(xMatch), + /*7552*/ uint16(xSetOp), uint16(PMULHUW), + /*7554*/ uint16(xReadSlashR), + /*7555*/ uint16(xArgXmm1), + /*7556*/ uint16(xArgXmm2M128), + /*7557*/ uint16(xMatch), + /*7558*/ uint16(xCondPrefix), 2, + 0x66, 7570, + 0x0, 7564, + /*7564*/ uint16(xSetOp), uint16(PMULHW), + /*7566*/ uint16(xReadSlashR), + /*7567*/ uint16(xArgMm), + /*7568*/ uint16(xArgMmM64), + /*7569*/ uint16(xMatch), + /*7570*/ uint16(xSetOp), uint16(PMULHW), + /*7572*/ uint16(xReadSlashR), + /*7573*/ uint16(xArgXmm1), + /*7574*/ uint16(xArgXmm2M128), + /*7575*/ uint16(xMatch), + /*7576*/ uint16(xCondPrefix), 3, + 0xF3, 7596, + 0xF2, 7590, + 0x66, 7584, + /*7584*/ uint16(xSetOp), uint16(CVTTPD2DQ), + /*7586*/ uint16(xReadSlashR), + /*7587*/ uint16(xArgXmm1), + /*7588*/ uint16(xArgXmm2M128), + /*7589*/ uint16(xMatch), + /*7590*/ uint16(xSetOp), uint16(CVTPD2DQ), + /*7592*/ uint16(xReadSlashR), + /*7593*/ uint16(xArgXmm1), + /*7594*/ uint16(xArgXmm2M128), + /*7595*/ uint16(xMatch), + /*7596*/ uint16(xSetOp), uint16(CVTDQ2PD), + /*7598*/ uint16(xReadSlashR), + /*7599*/ uint16(xArgXmm1), + /*7600*/ uint16(xArgXmm2M64), + /*7601*/ uint16(xMatch), + /*7602*/ uint16(xCondPrefix), 2, + 0x66, 7614, + 0x0, 7608, + /*7608*/ uint16(xSetOp), uint16(MOVNTQ), + /*7610*/ uint16(xReadSlashR), + /*7611*/ uint16(xArgM64), + /*7612*/ uint16(xArgMm), + /*7613*/ uint16(xMatch), + /*7614*/ uint16(xSetOp), uint16(MOVNTDQ), + /*7616*/ uint16(xReadSlashR), + /*7617*/ uint16(xArgM128), + /*7618*/ uint16(xArgXmm), + /*7619*/ uint16(xMatch), + /*7620*/ uint16(xCondPrefix), 2, + 0x66, 7632, + 0x0, 7626, + /*7626*/ uint16(xSetOp), uint16(PSUBSB), + /*7628*/ uint16(xReadSlashR), + /*7629*/ uint16(xArgMm), + /*7630*/ uint16(xArgMmM64), + /*7631*/ uint16(xMatch), + /*7632*/ uint16(xSetOp), uint16(PSUBSB), + /*7634*/ uint16(xReadSlashR), + /*7635*/ uint16(xArgXmm1), + /*7636*/ uint16(xArgXmm2M128), + /*7637*/ uint16(xMatch), + /*7638*/ uint16(xCondPrefix), 2, + 0x66, 7650, + 0x0, 7644, + /*7644*/ uint16(xSetOp), uint16(PSUBSW), + /*7646*/ uint16(xReadSlashR), + /*7647*/ uint16(xArgMm), + /*7648*/ uint16(xArgMmM64), + /*7649*/ uint16(xMatch), + /*7650*/ uint16(xSetOp), uint16(PSUBSW), + /*7652*/ uint16(xReadSlashR), + /*7653*/ uint16(xArgXmm1), + /*7654*/ uint16(xArgXmm2M128), + /*7655*/ uint16(xMatch), + /*7656*/ uint16(xCondPrefix), 2, + 0x66, 7668, + 0x0, 7662, + /*7662*/ uint16(xSetOp), uint16(PMINSW), + /*7664*/ uint16(xReadSlashR), + /*7665*/ uint16(xArgMm1), + /*7666*/ uint16(xArgMm2M64), + /*7667*/ uint16(xMatch), + /*7668*/ uint16(xSetOp), uint16(PMINSW), + /*7670*/ uint16(xReadSlashR), + /*7671*/ uint16(xArgXmm1), + /*7672*/ uint16(xArgXmm2M128), + /*7673*/ uint16(xMatch), + /*7674*/ uint16(xCondPrefix), 2, + 0x66, 7686, + 0x0, 7680, + /*7680*/ uint16(xSetOp), uint16(POR), + /*7682*/ uint16(xReadSlashR), + /*7683*/ uint16(xArgMm), + /*7684*/ uint16(xArgMmM64), + /*7685*/ uint16(xMatch), + /*7686*/ uint16(xSetOp), uint16(POR), + /*7688*/ uint16(xReadSlashR), + /*7689*/ uint16(xArgXmm1), + /*7690*/ uint16(xArgXmm2M128), + /*7691*/ uint16(xMatch), + /*7692*/ uint16(xCondPrefix), 2, + 0x66, 7704, + 0x0, 7698, + /*7698*/ uint16(xSetOp), uint16(PADDSB), + /*7700*/ uint16(xReadSlashR), + /*7701*/ uint16(xArgMm), + /*7702*/ uint16(xArgMmM64), + /*7703*/ uint16(xMatch), + /*7704*/ uint16(xSetOp), uint16(PADDSB), + /*7706*/ uint16(xReadSlashR), + /*7707*/ uint16(xArgXmm1), + /*7708*/ uint16(xArgXmm2M128), + /*7709*/ uint16(xMatch), + /*7710*/ uint16(xCondPrefix), 2, + 0x66, 7722, + 0x0, 7716, + /*7716*/ uint16(xSetOp), uint16(PADDSW), + /*7718*/ uint16(xReadSlashR), + /*7719*/ uint16(xArgMm), + /*7720*/ uint16(xArgMmM64), + /*7721*/ uint16(xMatch), + /*7722*/ uint16(xSetOp), uint16(PADDSW), + /*7724*/ uint16(xReadSlashR), + /*7725*/ uint16(xArgXmm1), + /*7726*/ uint16(xArgXmm2M128), + /*7727*/ uint16(xMatch), + /*7728*/ uint16(xCondPrefix), 2, + 0x66, 7740, + 0x0, 7734, + /*7734*/ uint16(xSetOp), uint16(PMAXSW), + /*7736*/ uint16(xReadSlashR), + /*7737*/ uint16(xArgMm1), + /*7738*/ uint16(xArgMm2M64), + /*7739*/ uint16(xMatch), + /*7740*/ uint16(xSetOp), uint16(PMAXSW), + /*7742*/ uint16(xReadSlashR), + /*7743*/ uint16(xArgXmm1), + /*7744*/ uint16(xArgXmm2M128), + /*7745*/ uint16(xMatch), + /*7746*/ uint16(xCondPrefix), 2, + 0x66, 7758, + 0x0, 7752, + /*7752*/ uint16(xSetOp), uint16(PXOR), + /*7754*/ uint16(xReadSlashR), + /*7755*/ uint16(xArgMm), + /*7756*/ uint16(xArgMmM64), + /*7757*/ uint16(xMatch), + /*7758*/ uint16(xSetOp), uint16(PXOR), + /*7760*/ uint16(xReadSlashR), + /*7761*/ uint16(xArgXmm1), + /*7762*/ uint16(xArgXmm2M128), + /*7763*/ uint16(xMatch), + /*7764*/ uint16(xCondPrefix), 1, + 0xF2, 7768, + /*7768*/ uint16(xSetOp), uint16(LDDQU), + /*7770*/ uint16(xReadSlashR), + /*7771*/ uint16(xArgXmm1), + /*7772*/ uint16(xArgM128), + /*7773*/ uint16(xMatch), + /*7774*/ uint16(xCondPrefix), 2, + 0x66, 7786, + 0x0, 7780, + /*7780*/ uint16(xSetOp), uint16(PSLLW), + /*7782*/ uint16(xReadSlashR), + /*7783*/ uint16(xArgMm), + /*7784*/ uint16(xArgMmM64), + /*7785*/ uint16(xMatch), + /*7786*/ uint16(xSetOp), uint16(PSLLW), + /*7788*/ uint16(xReadSlashR), + /*7789*/ uint16(xArgXmm1), + /*7790*/ uint16(xArgXmm2M128), + /*7791*/ uint16(xMatch), + /*7792*/ uint16(xCondPrefix), 2, + 0x66, 7804, + 0x0, 7798, + /*7798*/ uint16(xSetOp), uint16(PSLLD), + /*7800*/ uint16(xReadSlashR), + /*7801*/ uint16(xArgMm), + /*7802*/ uint16(xArgMmM64), + /*7803*/ uint16(xMatch), + /*7804*/ uint16(xSetOp), uint16(PSLLD), + /*7806*/ uint16(xReadSlashR), + /*7807*/ uint16(xArgXmm1), + /*7808*/ uint16(xArgXmm2M128), + /*7809*/ uint16(xMatch), + /*7810*/ uint16(xCondPrefix), 2, + 0x66, 7822, + 0x0, 7816, + /*7816*/ uint16(xSetOp), uint16(PSLLQ), + /*7818*/ uint16(xReadSlashR), + /*7819*/ uint16(xArgMm), + /*7820*/ uint16(xArgMmM64), + /*7821*/ uint16(xMatch), + /*7822*/ uint16(xSetOp), uint16(PSLLQ), + /*7824*/ uint16(xReadSlashR), + /*7825*/ uint16(xArgXmm1), + /*7826*/ uint16(xArgXmm2M128), + /*7827*/ uint16(xMatch), + /*7828*/ uint16(xCondPrefix), 2, + 0x66, 7840, + 0x0, 7834, + /*7834*/ uint16(xSetOp), uint16(PMULUDQ), + /*7836*/ uint16(xReadSlashR), + /*7837*/ uint16(xArgMm1), + /*7838*/ uint16(xArgMm2M64), + /*7839*/ uint16(xMatch), + /*7840*/ uint16(xSetOp), uint16(PMULUDQ), + /*7842*/ uint16(xReadSlashR), + /*7843*/ uint16(xArgXmm1), + /*7844*/ uint16(xArgXmm2M128), + /*7845*/ uint16(xMatch), + /*7846*/ uint16(xCondPrefix), 2, + 0x66, 7858, + 0x0, 7852, + /*7852*/ uint16(xSetOp), uint16(PMADDWD), + /*7854*/ uint16(xReadSlashR), + /*7855*/ uint16(xArgMm), + /*7856*/ uint16(xArgMmM64), + /*7857*/ uint16(xMatch), + /*7858*/ uint16(xSetOp), uint16(PMADDWD), + /*7860*/ uint16(xReadSlashR), + /*7861*/ uint16(xArgXmm1), + /*7862*/ uint16(xArgXmm2M128), + /*7863*/ uint16(xMatch), + /*7864*/ uint16(xCondPrefix), 2, + 0x66, 7876, + 0x0, 7870, + /*7870*/ uint16(xSetOp), uint16(PSADBW), + /*7872*/ uint16(xReadSlashR), + /*7873*/ uint16(xArgMm1), + /*7874*/ uint16(xArgMm2M64), + /*7875*/ uint16(xMatch), + /*7876*/ uint16(xSetOp), uint16(PSADBW), + /*7878*/ uint16(xReadSlashR), + /*7879*/ uint16(xArgXmm1), + /*7880*/ uint16(xArgXmm2M128), + /*7881*/ uint16(xMatch), + /*7882*/ uint16(xCondPrefix), 2, + 0x66, 7894, + 0x0, 7888, + /*7888*/ uint16(xSetOp), uint16(MASKMOVQ), + /*7890*/ uint16(xReadSlashR), + /*7891*/ uint16(xArgMm1), + /*7892*/ uint16(xArgMm2), + /*7893*/ uint16(xMatch), + /*7894*/ uint16(xSetOp), uint16(MASKMOVDQU), + /*7896*/ uint16(xReadSlashR), + /*7897*/ uint16(xArgXmm1), + /*7898*/ uint16(xArgXmm2), + /*7899*/ uint16(xMatch), + /*7900*/ uint16(xCondPrefix), 2, + 0x66, 7912, + 0x0, 7906, + /*7906*/ uint16(xSetOp), uint16(PSUBB), + /*7908*/ uint16(xReadSlashR), + /*7909*/ uint16(xArgMm), + /*7910*/ uint16(xArgMmM64), + /*7911*/ uint16(xMatch), + /*7912*/ uint16(xSetOp), uint16(PSUBB), + /*7914*/ uint16(xReadSlashR), + /*7915*/ uint16(xArgXmm1), + /*7916*/ uint16(xArgXmm2M128), + /*7917*/ uint16(xMatch), + /*7918*/ uint16(xCondPrefix), 2, + 0x66, 7930, + 0x0, 7924, + /*7924*/ uint16(xSetOp), uint16(PSUBW), + /*7926*/ uint16(xReadSlashR), + /*7927*/ uint16(xArgMm), + /*7928*/ uint16(xArgMmM64), + /*7929*/ uint16(xMatch), + /*7930*/ uint16(xSetOp), uint16(PSUBW), + /*7932*/ uint16(xReadSlashR), + /*7933*/ uint16(xArgXmm1), + /*7934*/ uint16(xArgXmm2M128), + /*7935*/ uint16(xMatch), + /*7936*/ uint16(xCondPrefix), 2, + 0x66, 7948, + 0x0, 7942, + /*7942*/ uint16(xSetOp), uint16(PSUBD), + /*7944*/ uint16(xReadSlashR), + /*7945*/ uint16(xArgMm), + /*7946*/ uint16(xArgMmM64), + /*7947*/ uint16(xMatch), + /*7948*/ uint16(xSetOp), uint16(PSUBD), + /*7950*/ uint16(xReadSlashR), + /*7951*/ uint16(xArgXmm1), + /*7952*/ uint16(xArgXmm2M128), + /*7953*/ uint16(xMatch), + /*7954*/ uint16(xCondPrefix), 2, + 0x66, 7966, + 0x0, 7960, + /*7960*/ uint16(xSetOp), uint16(PSUBQ), + /*7962*/ uint16(xReadSlashR), + /*7963*/ uint16(xArgMm1), + /*7964*/ uint16(xArgMm2M64), + /*7965*/ uint16(xMatch), + /*7966*/ uint16(xSetOp), uint16(PSUBQ), + /*7968*/ uint16(xReadSlashR), + /*7969*/ uint16(xArgXmm1), + /*7970*/ uint16(xArgXmm2M128), + /*7971*/ uint16(xMatch), + /*7972*/ uint16(xCondPrefix), 2, + 0x66, 7984, + 0x0, 7978, + /*7978*/ uint16(xSetOp), uint16(PADDB), + /*7980*/ uint16(xReadSlashR), + /*7981*/ uint16(xArgMm), + /*7982*/ uint16(xArgMmM64), + /*7983*/ uint16(xMatch), + /*7984*/ uint16(xSetOp), uint16(PADDB), + /*7986*/ uint16(xReadSlashR), + /*7987*/ uint16(xArgXmm1), + /*7988*/ uint16(xArgXmm2M128), + /*7989*/ uint16(xMatch), + /*7990*/ uint16(xCondPrefix), 2, + 0x66, 8002, + 0x0, 7996, + /*7996*/ uint16(xSetOp), uint16(PADDW), + /*7998*/ uint16(xReadSlashR), + /*7999*/ uint16(xArgMm), + /*8000*/ uint16(xArgMmM64), + /*8001*/ uint16(xMatch), + /*8002*/ uint16(xSetOp), uint16(PADDW), + /*8004*/ uint16(xReadSlashR), + /*8005*/ uint16(xArgXmm1), + /*8006*/ uint16(xArgXmm2M128), + /*8007*/ uint16(xMatch), + /*8008*/ uint16(xCondPrefix), 2, + 0x66, 8020, + 0x0, 8014, + /*8014*/ uint16(xSetOp), uint16(PADDD), + /*8016*/ uint16(xReadSlashR), + /*8017*/ uint16(xArgMm), + /*8018*/ uint16(xArgMmM64), + /*8019*/ uint16(xMatch), + /*8020*/ uint16(xSetOp), uint16(PADDD), + /*8022*/ uint16(xReadSlashR), + /*8023*/ uint16(xArgXmm1), + /*8024*/ uint16(xArgXmm2M128), + /*8025*/ uint16(xMatch), + /*8026*/ uint16(xSetOp), uint16(ADC), + /*8028*/ uint16(xReadSlashR), + /*8029*/ uint16(xArgRM8), + /*8030*/ uint16(xArgR8), + /*8031*/ uint16(xMatch), + /*8032*/ uint16(xCondIs64), 8035, 8051, + /*8035*/ uint16(xCondDataSize), 8039, 8045, 0, + /*8039*/ uint16(xSetOp), uint16(ADC), + /*8041*/ uint16(xReadSlashR), + /*8042*/ uint16(xArgRM16), + /*8043*/ uint16(xArgR16), + /*8044*/ uint16(xMatch), + /*8045*/ uint16(xSetOp), uint16(ADC), + /*8047*/ uint16(xReadSlashR), + /*8048*/ uint16(xArgRM32), + /*8049*/ uint16(xArgR32), + /*8050*/ uint16(xMatch), + /*8051*/ uint16(xCondDataSize), 8039, 8045, 8055, + /*8055*/ uint16(xSetOp), uint16(ADC), + /*8057*/ uint16(xReadSlashR), + /*8058*/ uint16(xArgRM64), + /*8059*/ uint16(xArgR64), + /*8060*/ uint16(xMatch), + /*8061*/ uint16(xSetOp), uint16(ADC), + /*8063*/ uint16(xReadSlashR), + /*8064*/ uint16(xArgR8), + /*8065*/ uint16(xArgRM8), + /*8066*/ uint16(xMatch), + /*8067*/ uint16(xCondIs64), 8070, 8086, + /*8070*/ uint16(xCondDataSize), 8074, 8080, 0, + /*8074*/ uint16(xSetOp), uint16(ADC), + /*8076*/ uint16(xReadSlashR), + /*8077*/ uint16(xArgR16), + /*8078*/ uint16(xArgRM16), + /*8079*/ uint16(xMatch), + /*8080*/ uint16(xSetOp), uint16(ADC), + /*8082*/ uint16(xReadSlashR), + /*8083*/ uint16(xArgR32), + /*8084*/ uint16(xArgRM32), + /*8085*/ uint16(xMatch), + /*8086*/ uint16(xCondDataSize), 8074, 8080, 8090, + /*8090*/ uint16(xSetOp), uint16(ADC), + /*8092*/ uint16(xReadSlashR), + /*8093*/ uint16(xArgR64), + /*8094*/ uint16(xArgRM64), + /*8095*/ uint16(xMatch), + /*8096*/ uint16(xSetOp), uint16(ADC), + /*8098*/ uint16(xReadIb), + /*8099*/ uint16(xArgAL), + /*8100*/ uint16(xArgImm8u), + /*8101*/ uint16(xMatch), + /*8102*/ uint16(xCondIs64), 8105, 8121, + /*8105*/ uint16(xCondDataSize), 8109, 8115, 0, + /*8109*/ uint16(xSetOp), uint16(ADC), + /*8111*/ uint16(xReadIw), + /*8112*/ uint16(xArgAX), + /*8113*/ uint16(xArgImm16), + /*8114*/ uint16(xMatch), + /*8115*/ uint16(xSetOp), uint16(ADC), + /*8117*/ uint16(xReadId), + /*8118*/ uint16(xArgEAX), + /*8119*/ uint16(xArgImm32), + /*8120*/ uint16(xMatch), + /*8121*/ uint16(xCondDataSize), 8109, 8115, 8125, + /*8125*/ uint16(xSetOp), uint16(ADC), + /*8127*/ uint16(xReadId), + /*8128*/ uint16(xArgRAX), + /*8129*/ uint16(xArgImm32), + /*8130*/ uint16(xMatch), + /*8131*/ uint16(xCondIs64), 8134, 0, + /*8134*/ uint16(xSetOp), uint16(PUSH), + /*8136*/ uint16(xArgSS), + /*8137*/ uint16(xMatch), + /*8138*/ uint16(xCondIs64), 8141, 0, + /*8141*/ uint16(xSetOp), uint16(POP), + /*8143*/ uint16(xArgSS), + /*8144*/ uint16(xMatch), + /*8145*/ uint16(xSetOp), uint16(SBB), + /*8147*/ uint16(xReadSlashR), + /*8148*/ uint16(xArgRM8), + /*8149*/ uint16(xArgR8), + /*8150*/ uint16(xMatch), + /*8151*/ uint16(xCondIs64), 8154, 8170, + /*8154*/ uint16(xCondDataSize), 8158, 8164, 0, + /*8158*/ uint16(xSetOp), uint16(SBB), + /*8160*/ uint16(xReadSlashR), + /*8161*/ uint16(xArgRM16), + /*8162*/ uint16(xArgR16), + /*8163*/ uint16(xMatch), + /*8164*/ uint16(xSetOp), uint16(SBB), + /*8166*/ uint16(xReadSlashR), + /*8167*/ uint16(xArgRM32), + /*8168*/ uint16(xArgR32), + /*8169*/ uint16(xMatch), + /*8170*/ uint16(xCondDataSize), 8158, 8164, 8174, + /*8174*/ uint16(xSetOp), uint16(SBB), + /*8176*/ uint16(xReadSlashR), + /*8177*/ uint16(xArgRM64), + /*8178*/ uint16(xArgR64), + /*8179*/ uint16(xMatch), + /*8180*/ uint16(xSetOp), uint16(SBB), + /*8182*/ uint16(xReadSlashR), + /*8183*/ uint16(xArgR8), + /*8184*/ uint16(xArgRM8), + /*8185*/ uint16(xMatch), + /*8186*/ uint16(xCondIs64), 8189, 8205, + /*8189*/ uint16(xCondDataSize), 8193, 8199, 0, + /*8193*/ uint16(xSetOp), uint16(SBB), + /*8195*/ uint16(xReadSlashR), + /*8196*/ uint16(xArgR16), + /*8197*/ uint16(xArgRM16), + /*8198*/ uint16(xMatch), + /*8199*/ uint16(xSetOp), uint16(SBB), + /*8201*/ uint16(xReadSlashR), + /*8202*/ uint16(xArgR32), + /*8203*/ uint16(xArgRM32), + /*8204*/ uint16(xMatch), + /*8205*/ uint16(xCondDataSize), 8193, 8199, 8209, + /*8209*/ uint16(xSetOp), uint16(SBB), + /*8211*/ uint16(xReadSlashR), + /*8212*/ uint16(xArgR64), + /*8213*/ uint16(xArgRM64), + /*8214*/ uint16(xMatch), + /*8215*/ uint16(xSetOp), uint16(SBB), + /*8217*/ uint16(xReadIb), + /*8218*/ uint16(xArgAL), + /*8219*/ uint16(xArgImm8u), + /*8220*/ uint16(xMatch), + /*8221*/ uint16(xCondIs64), 8224, 8240, + /*8224*/ uint16(xCondDataSize), 8228, 8234, 0, + /*8228*/ uint16(xSetOp), uint16(SBB), + /*8230*/ uint16(xReadIw), + /*8231*/ uint16(xArgAX), + /*8232*/ uint16(xArgImm16), + /*8233*/ uint16(xMatch), + /*8234*/ uint16(xSetOp), uint16(SBB), + /*8236*/ uint16(xReadId), + /*8237*/ uint16(xArgEAX), + /*8238*/ uint16(xArgImm32), + /*8239*/ uint16(xMatch), + /*8240*/ uint16(xCondDataSize), 8228, 8234, 8244, + /*8244*/ uint16(xSetOp), uint16(SBB), + /*8246*/ uint16(xReadId), + /*8247*/ uint16(xArgRAX), + /*8248*/ uint16(xArgImm32), + /*8249*/ uint16(xMatch), + /*8250*/ uint16(xCondIs64), 8253, 0, + /*8253*/ uint16(xSetOp), uint16(PUSH), + /*8255*/ uint16(xArgDS), + /*8256*/ uint16(xMatch), + /*8257*/ uint16(xCondIs64), 8260, 0, + /*8260*/ uint16(xSetOp), uint16(POP), + /*8262*/ uint16(xArgDS), + /*8263*/ uint16(xMatch), + /*8264*/ uint16(xSetOp), uint16(AND), + /*8266*/ uint16(xReadSlashR), + /*8267*/ uint16(xArgRM8), + /*8268*/ uint16(xArgR8), + /*8269*/ uint16(xMatch), + /*8270*/ uint16(xCondIs64), 8273, 8289, + /*8273*/ uint16(xCondDataSize), 8277, 8283, 0, + /*8277*/ uint16(xSetOp), uint16(AND), + /*8279*/ uint16(xReadSlashR), + /*8280*/ uint16(xArgRM16), + /*8281*/ uint16(xArgR16), + /*8282*/ uint16(xMatch), + /*8283*/ uint16(xSetOp), uint16(AND), + /*8285*/ uint16(xReadSlashR), + /*8286*/ uint16(xArgRM32), + /*8287*/ uint16(xArgR32), + /*8288*/ uint16(xMatch), + /*8289*/ uint16(xCondDataSize), 8277, 8283, 8293, + /*8293*/ uint16(xSetOp), uint16(AND), + /*8295*/ uint16(xReadSlashR), + /*8296*/ uint16(xArgRM64), + /*8297*/ uint16(xArgR64), + /*8298*/ uint16(xMatch), + /*8299*/ uint16(xSetOp), uint16(AND), + /*8301*/ uint16(xReadSlashR), + /*8302*/ uint16(xArgR8), + /*8303*/ uint16(xArgRM8), + /*8304*/ uint16(xMatch), + /*8305*/ uint16(xCondIs64), 8308, 8324, + /*8308*/ uint16(xCondDataSize), 8312, 8318, 0, + /*8312*/ uint16(xSetOp), uint16(AND), + /*8314*/ uint16(xReadSlashR), + /*8315*/ uint16(xArgR16), + /*8316*/ uint16(xArgRM16), + /*8317*/ uint16(xMatch), + /*8318*/ uint16(xSetOp), uint16(AND), + /*8320*/ uint16(xReadSlashR), + /*8321*/ uint16(xArgR32), + /*8322*/ uint16(xArgRM32), + /*8323*/ uint16(xMatch), + /*8324*/ uint16(xCondDataSize), 8312, 8318, 8328, + /*8328*/ uint16(xSetOp), uint16(AND), + /*8330*/ uint16(xReadSlashR), + /*8331*/ uint16(xArgR64), + /*8332*/ uint16(xArgRM64), + /*8333*/ uint16(xMatch), + /*8334*/ uint16(xSetOp), uint16(AND), + /*8336*/ uint16(xReadIb), + /*8337*/ uint16(xArgAL), + /*8338*/ uint16(xArgImm8u), + /*8339*/ uint16(xMatch), + /*8340*/ uint16(xCondIs64), 8343, 8359, + /*8343*/ uint16(xCondDataSize), 8347, 8353, 0, + /*8347*/ uint16(xSetOp), uint16(AND), + /*8349*/ uint16(xReadIw), + /*8350*/ uint16(xArgAX), + /*8351*/ uint16(xArgImm16), + /*8352*/ uint16(xMatch), + /*8353*/ uint16(xSetOp), uint16(AND), + /*8355*/ uint16(xReadId), + /*8356*/ uint16(xArgEAX), + /*8357*/ uint16(xArgImm32), + /*8358*/ uint16(xMatch), + /*8359*/ uint16(xCondDataSize), 8347, 8353, 8363, + /*8363*/ uint16(xSetOp), uint16(AND), + /*8365*/ uint16(xReadId), + /*8366*/ uint16(xArgRAX), + /*8367*/ uint16(xArgImm32), + /*8368*/ uint16(xMatch), + /*8369*/ uint16(xCondIs64), 8372, 0, + /*8372*/ uint16(xSetOp), uint16(DAA), + /*8374*/ uint16(xMatch), + /*8375*/ uint16(xSetOp), uint16(SUB), + /*8377*/ uint16(xReadSlashR), + /*8378*/ uint16(xArgRM8), + /*8379*/ uint16(xArgR8), + /*8380*/ uint16(xMatch), + /*8381*/ uint16(xCondIs64), 8384, 8400, + /*8384*/ uint16(xCondDataSize), 8388, 8394, 0, + /*8388*/ uint16(xSetOp), uint16(SUB), + /*8390*/ uint16(xReadSlashR), + /*8391*/ uint16(xArgRM16), + /*8392*/ uint16(xArgR16), + /*8393*/ uint16(xMatch), + /*8394*/ uint16(xSetOp), uint16(SUB), + /*8396*/ uint16(xReadSlashR), + /*8397*/ uint16(xArgRM32), + /*8398*/ uint16(xArgR32), + /*8399*/ uint16(xMatch), + /*8400*/ uint16(xCondDataSize), 8388, 8394, 8404, + /*8404*/ uint16(xSetOp), uint16(SUB), + /*8406*/ uint16(xReadSlashR), + /*8407*/ uint16(xArgRM64), + /*8408*/ uint16(xArgR64), + /*8409*/ uint16(xMatch), + /*8410*/ uint16(xSetOp), uint16(SUB), + /*8412*/ uint16(xReadSlashR), + /*8413*/ uint16(xArgR8), + /*8414*/ uint16(xArgRM8), + /*8415*/ uint16(xMatch), + /*8416*/ uint16(xCondIs64), 8419, 8435, + /*8419*/ uint16(xCondDataSize), 8423, 8429, 0, + /*8423*/ uint16(xSetOp), uint16(SUB), + /*8425*/ uint16(xReadSlashR), + /*8426*/ uint16(xArgR16), + /*8427*/ uint16(xArgRM16), + /*8428*/ uint16(xMatch), + /*8429*/ uint16(xSetOp), uint16(SUB), + /*8431*/ uint16(xReadSlashR), + /*8432*/ uint16(xArgR32), + /*8433*/ uint16(xArgRM32), + /*8434*/ uint16(xMatch), + /*8435*/ uint16(xCondDataSize), 8423, 8429, 8439, + /*8439*/ uint16(xSetOp), uint16(SUB), + /*8441*/ uint16(xReadSlashR), + /*8442*/ uint16(xArgR64), + /*8443*/ uint16(xArgRM64), + /*8444*/ uint16(xMatch), + /*8445*/ uint16(xSetOp), uint16(SUB), + /*8447*/ uint16(xReadIb), + /*8448*/ uint16(xArgAL), + /*8449*/ uint16(xArgImm8u), + /*8450*/ uint16(xMatch), + /*8451*/ uint16(xCondIs64), 8454, 8470, + /*8454*/ uint16(xCondDataSize), 8458, 8464, 0, + /*8458*/ uint16(xSetOp), uint16(SUB), + /*8460*/ uint16(xReadIw), + /*8461*/ uint16(xArgAX), + /*8462*/ uint16(xArgImm16), + /*8463*/ uint16(xMatch), + /*8464*/ uint16(xSetOp), uint16(SUB), + /*8466*/ uint16(xReadId), + /*8467*/ uint16(xArgEAX), + /*8468*/ uint16(xArgImm32), + /*8469*/ uint16(xMatch), + /*8470*/ uint16(xCondDataSize), 8458, 8464, 8474, + /*8474*/ uint16(xSetOp), uint16(SUB), + /*8476*/ uint16(xReadId), + /*8477*/ uint16(xArgRAX), + /*8478*/ uint16(xArgImm32), + /*8479*/ uint16(xMatch), + /*8480*/ uint16(xCondIs64), 8483, 0, + /*8483*/ uint16(xSetOp), uint16(DAS), + /*8485*/ uint16(xMatch), + /*8486*/ uint16(xSetOp), uint16(XOR), + /*8488*/ uint16(xReadSlashR), + /*8489*/ uint16(xArgRM8), + /*8490*/ uint16(xArgR8), + /*8491*/ uint16(xMatch), + /*8492*/ uint16(xCondIs64), 8495, 8511, + /*8495*/ uint16(xCondDataSize), 8499, 8505, 0, + /*8499*/ uint16(xSetOp), uint16(XOR), + /*8501*/ uint16(xReadSlashR), + /*8502*/ uint16(xArgRM16), + /*8503*/ uint16(xArgR16), + /*8504*/ uint16(xMatch), + /*8505*/ uint16(xSetOp), uint16(XOR), + /*8507*/ uint16(xReadSlashR), + /*8508*/ uint16(xArgRM32), + /*8509*/ uint16(xArgR32), + /*8510*/ uint16(xMatch), + /*8511*/ uint16(xCondDataSize), 8499, 8505, 8515, + /*8515*/ uint16(xSetOp), uint16(XOR), + /*8517*/ uint16(xReadSlashR), + /*8518*/ uint16(xArgRM64), + /*8519*/ uint16(xArgR64), + /*8520*/ uint16(xMatch), + /*8521*/ uint16(xSetOp), uint16(XOR), + /*8523*/ uint16(xReadSlashR), + /*8524*/ uint16(xArgR8), + /*8525*/ uint16(xArgRM8), + /*8526*/ uint16(xMatch), + /*8527*/ uint16(xCondIs64), 8530, 8546, + /*8530*/ uint16(xCondDataSize), 8534, 8540, 0, + /*8534*/ uint16(xSetOp), uint16(XOR), + /*8536*/ uint16(xReadSlashR), + /*8537*/ uint16(xArgR16), + /*8538*/ uint16(xArgRM16), + /*8539*/ uint16(xMatch), + /*8540*/ uint16(xSetOp), uint16(XOR), + /*8542*/ uint16(xReadSlashR), + /*8543*/ uint16(xArgR32), + /*8544*/ uint16(xArgRM32), + /*8545*/ uint16(xMatch), + /*8546*/ uint16(xCondDataSize), 8534, 8540, 8550, + /*8550*/ uint16(xSetOp), uint16(XOR), + /*8552*/ uint16(xReadSlashR), + /*8553*/ uint16(xArgR64), + /*8554*/ uint16(xArgRM64), + /*8555*/ uint16(xMatch), + /*8556*/ uint16(xSetOp), uint16(XOR), + /*8558*/ uint16(xReadIb), + /*8559*/ uint16(xArgAL), + /*8560*/ uint16(xArgImm8u), + /*8561*/ uint16(xMatch), + /*8562*/ uint16(xCondIs64), 8565, 8581, + /*8565*/ uint16(xCondDataSize), 8569, 8575, 0, + /*8569*/ uint16(xSetOp), uint16(XOR), + /*8571*/ uint16(xReadIw), + /*8572*/ uint16(xArgAX), + /*8573*/ uint16(xArgImm16), + /*8574*/ uint16(xMatch), + /*8575*/ uint16(xSetOp), uint16(XOR), + /*8577*/ uint16(xReadId), + /*8578*/ uint16(xArgEAX), + /*8579*/ uint16(xArgImm32), + /*8580*/ uint16(xMatch), + /*8581*/ uint16(xCondDataSize), 8569, 8575, 8585, + /*8585*/ uint16(xSetOp), uint16(XOR), + /*8587*/ uint16(xReadId), + /*8588*/ uint16(xArgRAX), + /*8589*/ uint16(xArgImm32), + /*8590*/ uint16(xMatch), + /*8591*/ uint16(xCondIs64), 8594, 0, + /*8594*/ uint16(xSetOp), uint16(AAA), + /*8596*/ uint16(xMatch), + /*8597*/ uint16(xSetOp), uint16(CMP), + /*8599*/ uint16(xReadSlashR), + /*8600*/ uint16(xArgRM8), + /*8601*/ uint16(xArgR8), + /*8602*/ uint16(xMatch), + /*8603*/ uint16(xCondIs64), 8606, 8622, + /*8606*/ uint16(xCondDataSize), 8610, 8616, 0, + /*8610*/ uint16(xSetOp), uint16(CMP), + /*8612*/ uint16(xReadSlashR), + /*8613*/ uint16(xArgRM16), + /*8614*/ uint16(xArgR16), + /*8615*/ uint16(xMatch), + /*8616*/ uint16(xSetOp), uint16(CMP), + /*8618*/ uint16(xReadSlashR), + /*8619*/ uint16(xArgRM32), + /*8620*/ uint16(xArgR32), + /*8621*/ uint16(xMatch), + /*8622*/ uint16(xCondDataSize), 8610, 8616, 8626, + /*8626*/ uint16(xSetOp), uint16(CMP), + /*8628*/ uint16(xReadSlashR), + /*8629*/ uint16(xArgRM64), + /*8630*/ uint16(xArgR64), + /*8631*/ uint16(xMatch), + /*8632*/ uint16(xSetOp), uint16(CMP), + /*8634*/ uint16(xReadSlashR), + /*8635*/ uint16(xArgR8), + /*8636*/ uint16(xArgRM8), + /*8637*/ uint16(xMatch), + /*8638*/ uint16(xCondIs64), 8641, 8657, + /*8641*/ uint16(xCondDataSize), 8645, 8651, 0, + /*8645*/ uint16(xSetOp), uint16(CMP), + /*8647*/ uint16(xReadSlashR), + /*8648*/ uint16(xArgR16), + /*8649*/ uint16(xArgRM16), + /*8650*/ uint16(xMatch), + /*8651*/ uint16(xSetOp), uint16(CMP), + /*8653*/ uint16(xReadSlashR), + /*8654*/ uint16(xArgR32), + /*8655*/ uint16(xArgRM32), + /*8656*/ uint16(xMatch), + /*8657*/ uint16(xCondDataSize), 8645, 8651, 8661, + /*8661*/ uint16(xSetOp), uint16(CMP), + /*8663*/ uint16(xReadSlashR), + /*8664*/ uint16(xArgR64), + /*8665*/ uint16(xArgRM64), + /*8666*/ uint16(xMatch), + /*8667*/ uint16(xSetOp), uint16(CMP), + /*8669*/ uint16(xReadIb), + /*8670*/ uint16(xArgAL), + /*8671*/ uint16(xArgImm8u), + /*8672*/ uint16(xMatch), + /*8673*/ uint16(xCondIs64), 8676, 8692, + /*8676*/ uint16(xCondDataSize), 8680, 8686, 0, + /*8680*/ uint16(xSetOp), uint16(CMP), + /*8682*/ uint16(xReadIw), + /*8683*/ uint16(xArgAX), + /*8684*/ uint16(xArgImm16), + /*8685*/ uint16(xMatch), + /*8686*/ uint16(xSetOp), uint16(CMP), + /*8688*/ uint16(xReadId), + /*8689*/ uint16(xArgEAX), + /*8690*/ uint16(xArgImm32), + /*8691*/ uint16(xMatch), + /*8692*/ uint16(xCondDataSize), 8680, 8686, 8696, + /*8696*/ uint16(xSetOp), uint16(CMP), + /*8698*/ uint16(xReadId), + /*8699*/ uint16(xArgRAX), + /*8700*/ uint16(xArgImm32), + /*8701*/ uint16(xMatch), + /*8702*/ uint16(xCondIs64), 8705, 0, + /*8705*/ uint16(xSetOp), uint16(AAS), + /*8707*/ uint16(xMatch), + /*8708*/ uint16(xCondIs64), 8711, 0, + /*8711*/ uint16(xCondDataSize), 8715, 8719, 0, + /*8715*/ uint16(xSetOp), uint16(INC), + /*8717*/ uint16(xArgR16op), + /*8718*/ uint16(xMatch), + /*8719*/ uint16(xSetOp), uint16(INC), + /*8721*/ uint16(xArgR32op), + /*8722*/ uint16(xMatch), + /*8723*/ uint16(xCondIs64), 8726, 0, + /*8726*/ uint16(xCondDataSize), 8730, 8734, 0, + /*8730*/ uint16(xSetOp), uint16(DEC), + /*8732*/ uint16(xArgR16op), + /*8733*/ uint16(xMatch), + /*8734*/ uint16(xSetOp), uint16(DEC), + /*8736*/ uint16(xArgR32op), + /*8737*/ uint16(xMatch), + /*8738*/ uint16(xCondIs64), 8741, 8753, + /*8741*/ uint16(xCondDataSize), 8745, 8749, 0, + /*8745*/ uint16(xSetOp), uint16(PUSH), + /*8747*/ uint16(xArgR16op), + /*8748*/ uint16(xMatch), + /*8749*/ uint16(xSetOp), uint16(PUSH), + /*8751*/ uint16(xArgR32op), + /*8752*/ uint16(xMatch), + /*8753*/ uint16(xCondDataSize), 8745, 8757, 8761, + /*8757*/ uint16(xSetOp), uint16(PUSH), + /*8759*/ uint16(xArgR64op), + /*8760*/ uint16(xMatch), + /*8761*/ uint16(xSetOp), uint16(PUSH), + /*8763*/ uint16(xArgR64op), + /*8764*/ uint16(xMatch), + /*8765*/ uint16(xCondIs64), 8768, 8780, + /*8768*/ uint16(xCondDataSize), 8772, 8776, 0, + /*8772*/ uint16(xSetOp), uint16(POP), + /*8774*/ uint16(xArgR16op), + /*8775*/ uint16(xMatch), + /*8776*/ uint16(xSetOp), uint16(POP), + /*8778*/ uint16(xArgR32op), + /*8779*/ uint16(xMatch), + /*8780*/ uint16(xCondDataSize), 8772, 8784, 8788, + /*8784*/ uint16(xSetOp), uint16(POP), + /*8786*/ uint16(xArgR64op), + /*8787*/ uint16(xMatch), + /*8788*/ uint16(xSetOp), uint16(POP), + /*8790*/ uint16(xArgR64op), + /*8791*/ uint16(xMatch), + /*8792*/ uint16(xCondIs64), 8795, 0, + /*8795*/ uint16(xCondDataSize), 8799, 8802, 0, + /*8799*/ uint16(xSetOp), uint16(PUSHA), + /*8801*/ uint16(xMatch), + /*8802*/ uint16(xSetOp), uint16(PUSHAD), + /*8804*/ uint16(xMatch), + /*8805*/ uint16(xCondIs64), 8808, 0, + /*8808*/ uint16(xCondDataSize), 8812, 8815, 0, + /*8812*/ uint16(xSetOp), uint16(POPA), + /*8814*/ uint16(xMatch), + /*8815*/ uint16(xSetOp), uint16(POPAD), + /*8817*/ uint16(xMatch), + /*8818*/ uint16(xCondIs64), 8821, 0, + /*8821*/ uint16(xCondDataSize), 8825, 8831, 0, + /*8825*/ uint16(xSetOp), uint16(BOUND), + /*8827*/ uint16(xReadSlashR), + /*8828*/ uint16(xArgR16), + /*8829*/ uint16(xArgM16and16), + /*8830*/ uint16(xMatch), + /*8831*/ uint16(xSetOp), uint16(BOUND), + /*8833*/ uint16(xReadSlashR), + /*8834*/ uint16(xArgR32), + /*8835*/ uint16(xArgM32and32), + /*8836*/ uint16(xMatch), + /*8837*/ uint16(xCondIs64), 8840, 8846, + /*8840*/ uint16(xSetOp), uint16(ARPL), + /*8842*/ uint16(xReadSlashR), + /*8843*/ uint16(xArgRM16), + /*8844*/ uint16(xArgR16), + /*8845*/ uint16(xMatch), + /*8846*/ uint16(xCondDataSize), 8850, 8856, 8862, + /*8850*/ uint16(xSetOp), uint16(MOVSXD), + /*8852*/ uint16(xReadSlashR), + /*8853*/ uint16(xArgR16), + /*8854*/ uint16(xArgRM32), + /*8855*/ uint16(xMatch), + /*8856*/ uint16(xSetOp), uint16(MOVSXD), + /*8858*/ uint16(xReadSlashR), + /*8859*/ uint16(xArgR32), + /*8860*/ uint16(xArgRM32), + /*8861*/ uint16(xMatch), + /*8862*/ uint16(xSetOp), uint16(MOVSXD), + /*8864*/ uint16(xReadSlashR), + /*8865*/ uint16(xArgR64), + /*8866*/ uint16(xArgRM32), + /*8867*/ uint16(xMatch), + /*8868*/ uint16(xCondDataSize), 8872, 8877, 8882, + /*8872*/ uint16(xSetOp), uint16(PUSH), + /*8874*/ uint16(xReadIw), + /*8875*/ uint16(xArgImm16), + /*8876*/ uint16(xMatch), + /*8877*/ uint16(xSetOp), uint16(PUSH), + /*8879*/ uint16(xReadId), + /*8880*/ uint16(xArgImm32), + /*8881*/ uint16(xMatch), + /*8882*/ uint16(xSetOp), uint16(PUSH), + /*8884*/ uint16(xReadId), + /*8885*/ uint16(xArgImm32), + /*8886*/ uint16(xMatch), + /*8887*/ uint16(xCondIs64), 8890, 8910, + /*8890*/ uint16(xCondDataSize), 8894, 8902, 0, + /*8894*/ uint16(xSetOp), uint16(IMUL), + /*8896*/ uint16(xReadSlashR), + /*8897*/ uint16(xReadIw), + /*8898*/ uint16(xArgR16), + /*8899*/ uint16(xArgRM16), + /*8900*/ uint16(xArgImm16), + /*8901*/ uint16(xMatch), + /*8902*/ uint16(xSetOp), uint16(IMUL), + /*8904*/ uint16(xReadSlashR), + /*8905*/ uint16(xReadId), + /*8906*/ uint16(xArgR32), + /*8907*/ uint16(xArgRM32), + /*8908*/ uint16(xArgImm32), + /*8909*/ uint16(xMatch), + /*8910*/ uint16(xCondDataSize), 8894, 8902, 8914, + /*8914*/ uint16(xSetOp), uint16(IMUL), + /*8916*/ uint16(xReadSlashR), + /*8917*/ uint16(xReadId), + /*8918*/ uint16(xArgR64), + /*8919*/ uint16(xArgRM64), + /*8920*/ uint16(xArgImm32), + /*8921*/ uint16(xMatch), + /*8922*/ uint16(xSetOp), uint16(PUSH), + /*8924*/ uint16(xReadIb), + /*8925*/ uint16(xArgImm8), + /*8926*/ uint16(xMatch), + /*8927*/ uint16(xCondIs64), 8930, 8950, + /*8930*/ uint16(xCondDataSize), 8934, 8942, 0, + /*8934*/ uint16(xSetOp), uint16(IMUL), + /*8936*/ uint16(xReadSlashR), + /*8937*/ uint16(xReadIb), + /*8938*/ uint16(xArgR16), + /*8939*/ uint16(xArgRM16), + /*8940*/ uint16(xArgImm8), + /*8941*/ uint16(xMatch), + /*8942*/ uint16(xSetOp), uint16(IMUL), + /*8944*/ uint16(xReadSlashR), + /*8945*/ uint16(xReadIb), + /*8946*/ uint16(xArgR32), + /*8947*/ uint16(xArgRM32), + /*8948*/ uint16(xArgImm8), + /*8949*/ uint16(xMatch), + /*8950*/ uint16(xCondDataSize), 8934, 8942, 8954, + /*8954*/ uint16(xSetOp), uint16(IMUL), + /*8956*/ uint16(xReadSlashR), + /*8957*/ uint16(xReadIb), + /*8958*/ uint16(xArgR64), + /*8959*/ uint16(xArgRM64), + /*8960*/ uint16(xArgImm8), + /*8961*/ uint16(xMatch), + /*8962*/ uint16(xSetOp), uint16(INSB), + /*8964*/ uint16(xMatch), + /*8965*/ uint16(xCondDataSize), 8969, 8972, 8975, + /*8969*/ uint16(xSetOp), uint16(INSW), + /*8971*/ uint16(xMatch), + /*8972*/ uint16(xSetOp), uint16(INSD), + /*8974*/ uint16(xMatch), + /*8975*/ uint16(xSetOp), uint16(INSD), + /*8977*/ uint16(xMatch), + /*8978*/ uint16(xSetOp), uint16(OUTSB), + /*8980*/ uint16(xMatch), + /*8981*/ uint16(xCondDataSize), 8985, 8988, 8991, + /*8985*/ uint16(xSetOp), uint16(OUTSW), + /*8987*/ uint16(xMatch), + /*8988*/ uint16(xSetOp), uint16(OUTSD), + /*8990*/ uint16(xMatch), + /*8991*/ uint16(xSetOp), uint16(OUTSD), + /*8993*/ uint16(xMatch), + /*8994*/ uint16(xSetOp), uint16(JO), + /*8996*/ uint16(xReadCb), + /*8997*/ uint16(xArgRel8), + /*8998*/ uint16(xMatch), + /*8999*/ uint16(xSetOp), uint16(JNO), + /*9001*/ uint16(xReadCb), + /*9002*/ uint16(xArgRel8), + /*9003*/ uint16(xMatch), + /*9004*/ uint16(xSetOp), uint16(JB), + /*9006*/ uint16(xReadCb), + /*9007*/ uint16(xArgRel8), + /*9008*/ uint16(xMatch), + /*9009*/ uint16(xSetOp), uint16(JAE), + /*9011*/ uint16(xReadCb), + /*9012*/ uint16(xArgRel8), + /*9013*/ uint16(xMatch), + /*9014*/ uint16(xSetOp), uint16(JE), + /*9016*/ uint16(xReadCb), + /*9017*/ uint16(xArgRel8), + /*9018*/ uint16(xMatch), + /*9019*/ uint16(xSetOp), uint16(JNE), + /*9021*/ uint16(xReadCb), + /*9022*/ uint16(xArgRel8), + /*9023*/ uint16(xMatch), + /*9024*/ uint16(xSetOp), uint16(JBE), + /*9026*/ uint16(xReadCb), + /*9027*/ uint16(xArgRel8), + /*9028*/ uint16(xMatch), + /*9029*/ uint16(xSetOp), uint16(JA), + /*9031*/ uint16(xReadCb), + /*9032*/ uint16(xArgRel8), + /*9033*/ uint16(xMatch), + /*9034*/ uint16(xSetOp), uint16(JS), + /*9036*/ uint16(xReadCb), + /*9037*/ uint16(xArgRel8), + /*9038*/ uint16(xMatch), + /*9039*/ uint16(xSetOp), uint16(JNS), + /*9041*/ uint16(xReadCb), + /*9042*/ uint16(xArgRel8), + /*9043*/ uint16(xMatch), + /*9044*/ uint16(xSetOp), uint16(JP), + /*9046*/ uint16(xReadCb), + /*9047*/ uint16(xArgRel8), + /*9048*/ uint16(xMatch), + /*9049*/ uint16(xSetOp), uint16(JNP), + /*9051*/ uint16(xReadCb), + /*9052*/ uint16(xArgRel8), + /*9053*/ uint16(xMatch), + /*9054*/ uint16(xSetOp), uint16(JL), + /*9056*/ uint16(xReadCb), + /*9057*/ uint16(xArgRel8), + /*9058*/ uint16(xMatch), + /*9059*/ uint16(xSetOp), uint16(JGE), + /*9061*/ uint16(xReadCb), + /*9062*/ uint16(xArgRel8), + /*9063*/ uint16(xMatch), + /*9064*/ uint16(xSetOp), uint16(JLE), + /*9066*/ uint16(xReadCb), + /*9067*/ uint16(xArgRel8), + /*9068*/ uint16(xMatch), + /*9069*/ uint16(xSetOp), uint16(JG), + /*9071*/ uint16(xReadCb), + /*9072*/ uint16(xArgRel8), + /*9073*/ uint16(xMatch), + /*9074*/ uint16(xCondSlashR), + 9083, // 0 + 9089, // 1 + 9095, // 2 + 9101, // 3 + 9107, // 4 + 9113, // 5 + 9119, // 6 + 9125, // 7 + /*9083*/ uint16(xSetOp), uint16(ADD), + /*9085*/ uint16(xReadIb), + /*9086*/ uint16(xArgRM8), + /*9087*/ uint16(xArgImm8u), + /*9088*/ uint16(xMatch), + /*9089*/ uint16(xSetOp), uint16(OR), + /*9091*/ uint16(xReadIb), + /*9092*/ uint16(xArgRM8), + /*9093*/ uint16(xArgImm8u), + /*9094*/ uint16(xMatch), + /*9095*/ uint16(xSetOp), uint16(ADC), + /*9097*/ uint16(xReadIb), + /*9098*/ uint16(xArgRM8), + /*9099*/ uint16(xArgImm8u), + /*9100*/ uint16(xMatch), + /*9101*/ uint16(xSetOp), uint16(SBB), + /*9103*/ uint16(xReadIb), + /*9104*/ uint16(xArgRM8), + /*9105*/ uint16(xArgImm8u), + /*9106*/ uint16(xMatch), + /*9107*/ uint16(xSetOp), uint16(AND), + /*9109*/ uint16(xReadIb), + /*9110*/ uint16(xArgRM8), + /*9111*/ uint16(xArgImm8u), + /*9112*/ uint16(xMatch), + /*9113*/ uint16(xSetOp), uint16(SUB), + /*9115*/ uint16(xReadIb), + /*9116*/ uint16(xArgRM8), + /*9117*/ uint16(xArgImm8u), + /*9118*/ uint16(xMatch), + /*9119*/ uint16(xSetOp), uint16(XOR), + /*9121*/ uint16(xReadIb), + /*9122*/ uint16(xArgRM8), + /*9123*/ uint16(xArgImm8u), + /*9124*/ uint16(xMatch), + /*9125*/ uint16(xSetOp), uint16(CMP), + /*9127*/ uint16(xReadIb), + /*9128*/ uint16(xArgRM8), + /*9129*/ uint16(xArgImm8u), + /*9130*/ uint16(xMatch), + /*9131*/ uint16(xCondSlashR), + 9140, // 0 + 9169, // 1 + 9198, // 2 + 9227, // 3 + 9256, // 4 + 9285, // 5 + 9314, // 6 + 9343, // 7 + /*9140*/ uint16(xCondIs64), 9143, 9159, + /*9143*/ uint16(xCondDataSize), 9147, 9153, 0, + /*9147*/ uint16(xSetOp), uint16(ADD), + /*9149*/ uint16(xReadIw), + /*9150*/ uint16(xArgRM16), + /*9151*/ uint16(xArgImm16), + /*9152*/ uint16(xMatch), + /*9153*/ uint16(xSetOp), uint16(ADD), + /*9155*/ uint16(xReadId), + /*9156*/ uint16(xArgRM32), + /*9157*/ uint16(xArgImm32), + /*9158*/ uint16(xMatch), + /*9159*/ uint16(xCondDataSize), 9147, 9153, 9163, + /*9163*/ uint16(xSetOp), uint16(ADD), + /*9165*/ uint16(xReadId), + /*9166*/ uint16(xArgRM64), + /*9167*/ uint16(xArgImm32), + /*9168*/ uint16(xMatch), + /*9169*/ uint16(xCondIs64), 9172, 9188, + /*9172*/ uint16(xCondDataSize), 9176, 9182, 0, + /*9176*/ uint16(xSetOp), uint16(OR), + /*9178*/ uint16(xReadIw), + /*9179*/ uint16(xArgRM16), + /*9180*/ uint16(xArgImm16), + /*9181*/ uint16(xMatch), + /*9182*/ uint16(xSetOp), uint16(OR), + /*9184*/ uint16(xReadId), + /*9185*/ uint16(xArgRM32), + /*9186*/ uint16(xArgImm32), + /*9187*/ uint16(xMatch), + /*9188*/ uint16(xCondDataSize), 9176, 9182, 9192, + /*9192*/ uint16(xSetOp), uint16(OR), + /*9194*/ uint16(xReadId), + /*9195*/ uint16(xArgRM64), + /*9196*/ uint16(xArgImm32), + /*9197*/ uint16(xMatch), + /*9198*/ uint16(xCondIs64), 9201, 9217, + /*9201*/ uint16(xCondDataSize), 9205, 9211, 0, + /*9205*/ uint16(xSetOp), uint16(ADC), + /*9207*/ uint16(xReadIw), + /*9208*/ uint16(xArgRM16), + /*9209*/ uint16(xArgImm16), + /*9210*/ uint16(xMatch), + /*9211*/ uint16(xSetOp), uint16(ADC), + /*9213*/ uint16(xReadId), + /*9214*/ uint16(xArgRM32), + /*9215*/ uint16(xArgImm32), + /*9216*/ uint16(xMatch), + /*9217*/ uint16(xCondDataSize), 9205, 9211, 9221, + /*9221*/ uint16(xSetOp), uint16(ADC), + /*9223*/ uint16(xReadId), + /*9224*/ uint16(xArgRM64), + /*9225*/ uint16(xArgImm32), + /*9226*/ uint16(xMatch), + /*9227*/ uint16(xCondIs64), 9230, 9246, + /*9230*/ uint16(xCondDataSize), 9234, 9240, 0, + /*9234*/ uint16(xSetOp), uint16(SBB), + /*9236*/ uint16(xReadIw), + /*9237*/ uint16(xArgRM16), + /*9238*/ uint16(xArgImm16), + /*9239*/ uint16(xMatch), + /*9240*/ uint16(xSetOp), uint16(SBB), + /*9242*/ uint16(xReadId), + /*9243*/ uint16(xArgRM32), + /*9244*/ uint16(xArgImm32), + /*9245*/ uint16(xMatch), + /*9246*/ uint16(xCondDataSize), 9234, 9240, 9250, + /*9250*/ uint16(xSetOp), uint16(SBB), + /*9252*/ uint16(xReadId), + /*9253*/ uint16(xArgRM64), + /*9254*/ uint16(xArgImm32), + /*9255*/ uint16(xMatch), + /*9256*/ uint16(xCondIs64), 9259, 9275, + /*9259*/ uint16(xCondDataSize), 9263, 9269, 0, + /*9263*/ uint16(xSetOp), uint16(AND), + /*9265*/ uint16(xReadIw), + /*9266*/ uint16(xArgRM16), + /*9267*/ uint16(xArgImm16), + /*9268*/ uint16(xMatch), + /*9269*/ uint16(xSetOp), uint16(AND), + /*9271*/ uint16(xReadId), + /*9272*/ uint16(xArgRM32), + /*9273*/ uint16(xArgImm32), + /*9274*/ uint16(xMatch), + /*9275*/ uint16(xCondDataSize), 9263, 9269, 9279, + /*9279*/ uint16(xSetOp), uint16(AND), + /*9281*/ uint16(xReadId), + /*9282*/ uint16(xArgRM64), + /*9283*/ uint16(xArgImm32), + /*9284*/ uint16(xMatch), + /*9285*/ uint16(xCondIs64), 9288, 9304, + /*9288*/ uint16(xCondDataSize), 9292, 9298, 0, + /*9292*/ uint16(xSetOp), uint16(SUB), + /*9294*/ uint16(xReadIw), + /*9295*/ uint16(xArgRM16), + /*9296*/ uint16(xArgImm16), + /*9297*/ uint16(xMatch), + /*9298*/ uint16(xSetOp), uint16(SUB), + /*9300*/ uint16(xReadId), + /*9301*/ uint16(xArgRM32), + /*9302*/ uint16(xArgImm32), + /*9303*/ uint16(xMatch), + /*9304*/ uint16(xCondDataSize), 9292, 9298, 9308, + /*9308*/ uint16(xSetOp), uint16(SUB), + /*9310*/ uint16(xReadId), + /*9311*/ uint16(xArgRM64), + /*9312*/ uint16(xArgImm32), + /*9313*/ uint16(xMatch), + /*9314*/ uint16(xCondIs64), 9317, 9333, + /*9317*/ uint16(xCondDataSize), 9321, 9327, 0, + /*9321*/ uint16(xSetOp), uint16(XOR), + /*9323*/ uint16(xReadIw), + /*9324*/ uint16(xArgRM16), + /*9325*/ uint16(xArgImm16), + /*9326*/ uint16(xMatch), + /*9327*/ uint16(xSetOp), uint16(XOR), + /*9329*/ uint16(xReadId), + /*9330*/ uint16(xArgRM32), + /*9331*/ uint16(xArgImm32), + /*9332*/ uint16(xMatch), + /*9333*/ uint16(xCondDataSize), 9321, 9327, 9337, + /*9337*/ uint16(xSetOp), uint16(XOR), + /*9339*/ uint16(xReadId), + /*9340*/ uint16(xArgRM64), + /*9341*/ uint16(xArgImm32), + /*9342*/ uint16(xMatch), + /*9343*/ uint16(xCondIs64), 9346, 9362, + /*9346*/ uint16(xCondDataSize), 9350, 9356, 0, + /*9350*/ uint16(xSetOp), uint16(CMP), + /*9352*/ uint16(xReadIw), + /*9353*/ uint16(xArgRM16), + /*9354*/ uint16(xArgImm16), + /*9355*/ uint16(xMatch), + /*9356*/ uint16(xSetOp), uint16(CMP), + /*9358*/ uint16(xReadId), + /*9359*/ uint16(xArgRM32), + /*9360*/ uint16(xArgImm32), + /*9361*/ uint16(xMatch), + /*9362*/ uint16(xCondDataSize), 9350, 9356, 9366, + /*9366*/ uint16(xSetOp), uint16(CMP), + /*9368*/ uint16(xReadId), + /*9369*/ uint16(xArgRM64), + /*9370*/ uint16(xArgImm32), + /*9371*/ uint16(xMatch), + /*9372*/ uint16(xCondSlashR), + 9381, // 0 + 9410, // 1 + 9439, // 2 + 9468, // 3 + 9497, // 4 + 9526, // 5 + 9555, // 6 + 9584, // 7 + /*9381*/ uint16(xCondIs64), 9384, 9400, + /*9384*/ uint16(xCondDataSize), 9388, 9394, 0, + /*9388*/ uint16(xSetOp), uint16(ADD), + /*9390*/ uint16(xReadIb), + /*9391*/ uint16(xArgRM16), + /*9392*/ uint16(xArgImm8), + /*9393*/ uint16(xMatch), + /*9394*/ uint16(xSetOp), uint16(ADD), + /*9396*/ uint16(xReadIb), + /*9397*/ uint16(xArgRM32), + /*9398*/ uint16(xArgImm8), + /*9399*/ uint16(xMatch), + /*9400*/ uint16(xCondDataSize), 9388, 9394, 9404, + /*9404*/ uint16(xSetOp), uint16(ADD), + /*9406*/ uint16(xReadIb), + /*9407*/ uint16(xArgRM64), + /*9408*/ uint16(xArgImm8), + /*9409*/ uint16(xMatch), + /*9410*/ uint16(xCondIs64), 9413, 9429, + /*9413*/ uint16(xCondDataSize), 9417, 9423, 0, + /*9417*/ uint16(xSetOp), uint16(OR), + /*9419*/ uint16(xReadIb), + /*9420*/ uint16(xArgRM16), + /*9421*/ uint16(xArgImm8), + /*9422*/ uint16(xMatch), + /*9423*/ uint16(xSetOp), uint16(OR), + /*9425*/ uint16(xReadIb), + /*9426*/ uint16(xArgRM32), + /*9427*/ uint16(xArgImm8), + /*9428*/ uint16(xMatch), + /*9429*/ uint16(xCondDataSize), 9417, 9423, 9433, + /*9433*/ uint16(xSetOp), uint16(OR), + /*9435*/ uint16(xReadIb), + /*9436*/ uint16(xArgRM64), + /*9437*/ uint16(xArgImm8), + /*9438*/ uint16(xMatch), + /*9439*/ uint16(xCondIs64), 9442, 9458, + /*9442*/ uint16(xCondDataSize), 9446, 9452, 0, + /*9446*/ uint16(xSetOp), uint16(ADC), + /*9448*/ uint16(xReadIb), + /*9449*/ uint16(xArgRM16), + /*9450*/ uint16(xArgImm8), + /*9451*/ uint16(xMatch), + /*9452*/ uint16(xSetOp), uint16(ADC), + /*9454*/ uint16(xReadIb), + /*9455*/ uint16(xArgRM32), + /*9456*/ uint16(xArgImm8), + /*9457*/ uint16(xMatch), + /*9458*/ uint16(xCondDataSize), 9446, 9452, 9462, + /*9462*/ uint16(xSetOp), uint16(ADC), + /*9464*/ uint16(xReadIb), + /*9465*/ uint16(xArgRM64), + /*9466*/ uint16(xArgImm8), + /*9467*/ uint16(xMatch), + /*9468*/ uint16(xCondIs64), 9471, 9487, + /*9471*/ uint16(xCondDataSize), 9475, 9481, 0, + /*9475*/ uint16(xSetOp), uint16(SBB), + /*9477*/ uint16(xReadIb), + /*9478*/ uint16(xArgRM16), + /*9479*/ uint16(xArgImm8), + /*9480*/ uint16(xMatch), + /*9481*/ uint16(xSetOp), uint16(SBB), + /*9483*/ uint16(xReadIb), + /*9484*/ uint16(xArgRM32), + /*9485*/ uint16(xArgImm8), + /*9486*/ uint16(xMatch), + /*9487*/ uint16(xCondDataSize), 9475, 9481, 9491, + /*9491*/ uint16(xSetOp), uint16(SBB), + /*9493*/ uint16(xReadIb), + /*9494*/ uint16(xArgRM64), + /*9495*/ uint16(xArgImm8), + /*9496*/ uint16(xMatch), + /*9497*/ uint16(xCondIs64), 9500, 9516, + /*9500*/ uint16(xCondDataSize), 9504, 9510, 0, + /*9504*/ uint16(xSetOp), uint16(AND), + /*9506*/ uint16(xReadIb), + /*9507*/ uint16(xArgRM16), + /*9508*/ uint16(xArgImm8), + /*9509*/ uint16(xMatch), + /*9510*/ uint16(xSetOp), uint16(AND), + /*9512*/ uint16(xReadIb), + /*9513*/ uint16(xArgRM32), + /*9514*/ uint16(xArgImm8), + /*9515*/ uint16(xMatch), + /*9516*/ uint16(xCondDataSize), 9504, 9510, 9520, + /*9520*/ uint16(xSetOp), uint16(AND), + /*9522*/ uint16(xReadIb), + /*9523*/ uint16(xArgRM64), + /*9524*/ uint16(xArgImm8), + /*9525*/ uint16(xMatch), + /*9526*/ uint16(xCondIs64), 9529, 9545, + /*9529*/ uint16(xCondDataSize), 9533, 9539, 0, + /*9533*/ uint16(xSetOp), uint16(SUB), + /*9535*/ uint16(xReadIb), + /*9536*/ uint16(xArgRM16), + /*9537*/ uint16(xArgImm8), + /*9538*/ uint16(xMatch), + /*9539*/ uint16(xSetOp), uint16(SUB), + /*9541*/ uint16(xReadIb), + /*9542*/ uint16(xArgRM32), + /*9543*/ uint16(xArgImm8), + /*9544*/ uint16(xMatch), + /*9545*/ uint16(xCondDataSize), 9533, 9539, 9549, + /*9549*/ uint16(xSetOp), uint16(SUB), + /*9551*/ uint16(xReadIb), + /*9552*/ uint16(xArgRM64), + /*9553*/ uint16(xArgImm8), + /*9554*/ uint16(xMatch), + /*9555*/ uint16(xCondIs64), 9558, 9574, + /*9558*/ uint16(xCondDataSize), 9562, 9568, 0, + /*9562*/ uint16(xSetOp), uint16(XOR), + /*9564*/ uint16(xReadIb), + /*9565*/ uint16(xArgRM16), + /*9566*/ uint16(xArgImm8), + /*9567*/ uint16(xMatch), + /*9568*/ uint16(xSetOp), uint16(XOR), + /*9570*/ uint16(xReadIb), + /*9571*/ uint16(xArgRM32), + /*9572*/ uint16(xArgImm8), + /*9573*/ uint16(xMatch), + /*9574*/ uint16(xCondDataSize), 9562, 9568, 9578, + /*9578*/ uint16(xSetOp), uint16(XOR), + /*9580*/ uint16(xReadIb), + /*9581*/ uint16(xArgRM64), + /*9582*/ uint16(xArgImm8), + /*9583*/ uint16(xMatch), + /*9584*/ uint16(xCondIs64), 9587, 9603, + /*9587*/ uint16(xCondDataSize), 9591, 9597, 0, + /*9591*/ uint16(xSetOp), uint16(CMP), + /*9593*/ uint16(xReadIb), + /*9594*/ uint16(xArgRM16), + /*9595*/ uint16(xArgImm8), + /*9596*/ uint16(xMatch), + /*9597*/ uint16(xSetOp), uint16(CMP), + /*9599*/ uint16(xReadIb), + /*9600*/ uint16(xArgRM32), + /*9601*/ uint16(xArgImm8), + /*9602*/ uint16(xMatch), + /*9603*/ uint16(xCondDataSize), 9591, 9597, 9607, + /*9607*/ uint16(xSetOp), uint16(CMP), + /*9609*/ uint16(xReadIb), + /*9610*/ uint16(xArgRM64), + /*9611*/ uint16(xArgImm8), + /*9612*/ uint16(xMatch), + /*9613*/ uint16(xSetOp), uint16(TEST), + /*9615*/ uint16(xReadSlashR), + /*9616*/ uint16(xArgRM8), + /*9617*/ uint16(xArgR8), + /*9618*/ uint16(xMatch), + /*9619*/ uint16(xCondIs64), 9622, 9638, + /*9622*/ uint16(xCondDataSize), 9626, 9632, 0, + /*9626*/ uint16(xSetOp), uint16(TEST), + /*9628*/ uint16(xReadSlashR), + /*9629*/ uint16(xArgRM16), + /*9630*/ uint16(xArgR16), + /*9631*/ uint16(xMatch), + /*9632*/ uint16(xSetOp), uint16(TEST), + /*9634*/ uint16(xReadSlashR), + /*9635*/ uint16(xArgRM32), + /*9636*/ uint16(xArgR32), + /*9637*/ uint16(xMatch), + /*9638*/ uint16(xCondDataSize), 9626, 9632, 9642, + /*9642*/ uint16(xSetOp), uint16(TEST), + /*9644*/ uint16(xReadSlashR), + /*9645*/ uint16(xArgRM64), + /*9646*/ uint16(xArgR64), + /*9647*/ uint16(xMatch), + /*9648*/ uint16(xSetOp), uint16(XCHG), + /*9650*/ uint16(xReadSlashR), + /*9651*/ uint16(xArgRM8), + /*9652*/ uint16(xArgR8), + /*9653*/ uint16(xMatch), + /*9654*/ uint16(xCondIs64), 9657, 9673, + /*9657*/ uint16(xCondDataSize), 9661, 9667, 0, + /*9661*/ uint16(xSetOp), uint16(XCHG), + /*9663*/ uint16(xReadSlashR), + /*9664*/ uint16(xArgRM16), + /*9665*/ uint16(xArgR16), + /*9666*/ uint16(xMatch), + /*9667*/ uint16(xSetOp), uint16(XCHG), + /*9669*/ uint16(xReadSlashR), + /*9670*/ uint16(xArgRM32), + /*9671*/ uint16(xArgR32), + /*9672*/ uint16(xMatch), + /*9673*/ uint16(xCondDataSize), 9661, 9667, 9677, + /*9677*/ uint16(xSetOp), uint16(XCHG), + /*9679*/ uint16(xReadSlashR), + /*9680*/ uint16(xArgRM64), + /*9681*/ uint16(xArgR64), + /*9682*/ uint16(xMatch), + /*9683*/ uint16(xSetOp), uint16(MOV), + /*9685*/ uint16(xReadSlashR), + /*9686*/ uint16(xArgRM8), + /*9687*/ uint16(xArgR8), + /*9688*/ uint16(xMatch), + /*9689*/ uint16(xCondDataSize), 9693, 9699, 9705, + /*9693*/ uint16(xSetOp), uint16(MOV), + /*9695*/ uint16(xReadSlashR), + /*9696*/ uint16(xArgRM16), + /*9697*/ uint16(xArgR16), + /*9698*/ uint16(xMatch), + /*9699*/ uint16(xSetOp), uint16(MOV), + /*9701*/ uint16(xReadSlashR), + /*9702*/ uint16(xArgRM32), + /*9703*/ uint16(xArgR32), + /*9704*/ uint16(xMatch), + /*9705*/ uint16(xSetOp), uint16(MOV), + /*9707*/ uint16(xReadSlashR), + /*9708*/ uint16(xArgRM64), + /*9709*/ uint16(xArgR64), + /*9710*/ uint16(xMatch), + /*9711*/ uint16(xSetOp), uint16(MOV), + /*9713*/ uint16(xReadSlashR), + /*9714*/ uint16(xArgR8), + /*9715*/ uint16(xArgRM8), + /*9716*/ uint16(xMatch), + /*9717*/ uint16(xCondDataSize), 9721, 9727, 9733, + /*9721*/ uint16(xSetOp), uint16(MOV), + /*9723*/ uint16(xReadSlashR), + /*9724*/ uint16(xArgR16), + /*9725*/ uint16(xArgRM16), + /*9726*/ uint16(xMatch), + /*9727*/ uint16(xSetOp), uint16(MOV), + /*9729*/ uint16(xReadSlashR), + /*9730*/ uint16(xArgR32), + /*9731*/ uint16(xArgRM32), + /*9732*/ uint16(xMatch), + /*9733*/ uint16(xSetOp), uint16(MOV), + /*9735*/ uint16(xReadSlashR), + /*9736*/ uint16(xArgR64), + /*9737*/ uint16(xArgRM64), + /*9738*/ uint16(xMatch), + /*9739*/ uint16(xCondIs64), 9742, 9758, + /*9742*/ uint16(xCondDataSize), 9746, 9752, 0, + /*9746*/ uint16(xSetOp), uint16(MOV), + /*9748*/ uint16(xReadSlashR), + /*9749*/ uint16(xArgRM16), + /*9750*/ uint16(xArgSreg), + /*9751*/ uint16(xMatch), + /*9752*/ uint16(xSetOp), uint16(MOV), + /*9754*/ uint16(xReadSlashR), + /*9755*/ uint16(xArgR32M16), + /*9756*/ uint16(xArgSreg), + /*9757*/ uint16(xMatch), + /*9758*/ uint16(xCondDataSize), 9746, 9752, 9762, + /*9762*/ uint16(xSetOp), uint16(MOV), + /*9764*/ uint16(xReadSlashR), + /*9765*/ uint16(xArgR64M16), + /*9766*/ uint16(xArgSreg), + /*9767*/ uint16(xMatch), + /*9768*/ uint16(xCondIs64), 9771, 9787, + /*9771*/ uint16(xCondDataSize), 9775, 9781, 0, + /*9775*/ uint16(xSetOp), uint16(LEA), + /*9777*/ uint16(xReadSlashR), + /*9778*/ uint16(xArgR16), + /*9779*/ uint16(xArgM), + /*9780*/ uint16(xMatch), + /*9781*/ uint16(xSetOp), uint16(LEA), + /*9783*/ uint16(xReadSlashR), + /*9784*/ uint16(xArgR32), + /*9785*/ uint16(xArgM), + /*9786*/ uint16(xMatch), + /*9787*/ uint16(xCondDataSize), 9775, 9781, 9791, + /*9791*/ uint16(xSetOp), uint16(LEA), + /*9793*/ uint16(xReadSlashR), + /*9794*/ uint16(xArgR64), + /*9795*/ uint16(xArgM), + /*9796*/ uint16(xMatch), + /*9797*/ uint16(xCondIs64), 9800, 9816, + /*9800*/ uint16(xCondDataSize), 9804, 9810, 0, + /*9804*/ uint16(xSetOp), uint16(MOV), + /*9806*/ uint16(xReadSlashR), + /*9807*/ uint16(xArgSreg), + /*9808*/ uint16(xArgRM16), + /*9809*/ uint16(xMatch), + /*9810*/ uint16(xSetOp), uint16(MOV), + /*9812*/ uint16(xReadSlashR), + /*9813*/ uint16(xArgSreg), + /*9814*/ uint16(xArgR32M16), + /*9815*/ uint16(xMatch), + /*9816*/ uint16(xCondDataSize), 9804, 9810, 9820, + /*9820*/ uint16(xSetOp), uint16(MOV), + /*9822*/ uint16(xReadSlashR), + /*9823*/ uint16(xArgSreg), + /*9824*/ uint16(xArgR64M16), + /*9825*/ uint16(xMatch), + /*9826*/ uint16(xCondSlashR), + 9835, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*9835*/ uint16(xCondIs64), 9838, 9850, + /*9838*/ uint16(xCondDataSize), 9842, 9846, 0, + /*9842*/ uint16(xSetOp), uint16(POP), + /*9844*/ uint16(xArgRM16), + /*9845*/ uint16(xMatch), + /*9846*/ uint16(xSetOp), uint16(POP), + /*9848*/ uint16(xArgRM32), + /*9849*/ uint16(xMatch), + /*9850*/ uint16(xCondDataSize), 9842, 9854, 9858, + /*9854*/ uint16(xSetOp), uint16(POP), + /*9856*/ uint16(xArgRM64), + /*9857*/ uint16(xMatch), + /*9858*/ uint16(xSetOp), uint16(POP), + /*9860*/ uint16(xArgRM64), + /*9861*/ uint16(xMatch), + /*9862*/ uint16(xCondIs64), 9865, 9879, + /*9865*/ uint16(xCondDataSize), 9869, 9874, 0, + /*9869*/ uint16(xSetOp), uint16(XCHG), + /*9871*/ uint16(xArgR16op), + /*9872*/ uint16(xArgAX), + /*9873*/ uint16(xMatch), + /*9874*/ uint16(xSetOp), uint16(XCHG), + /*9876*/ uint16(xArgR32op), + /*9877*/ uint16(xArgEAX), + /*9878*/ uint16(xMatch), + /*9879*/ uint16(xCondDataSize), 9869, 9874, 9883, + /*9883*/ uint16(xSetOp), uint16(XCHG), + /*9885*/ uint16(xArgR64op), + /*9886*/ uint16(xArgRAX), + /*9887*/ uint16(xMatch), + /*9888*/ uint16(xCondIs64), 9891, 9901, + /*9891*/ uint16(xCondDataSize), 9895, 9898, 0, + /*9895*/ uint16(xSetOp), uint16(CBW), + /*9897*/ uint16(xMatch), + /*9898*/ uint16(xSetOp), uint16(CWDE), + /*9900*/ uint16(xMatch), + /*9901*/ uint16(xCondDataSize), 9895, 9898, 9905, + /*9905*/ uint16(xSetOp), uint16(CDQE), + /*9907*/ uint16(xMatch), + /*9908*/ uint16(xCondIs64), 9911, 9921, + /*9911*/ uint16(xCondDataSize), 9915, 9918, 0, + /*9915*/ uint16(xSetOp), uint16(CWD), + /*9917*/ uint16(xMatch), + /*9918*/ uint16(xSetOp), uint16(CDQ), + /*9920*/ uint16(xMatch), + /*9921*/ uint16(xCondDataSize), 9915, 9918, 9925, + /*9925*/ uint16(xSetOp), uint16(CQO), + /*9927*/ uint16(xMatch), + /*9928*/ uint16(xCondIs64), 9931, 0, + /*9931*/ uint16(xCondDataSize), 9935, 9940, 0, + /*9935*/ uint16(xSetOp), uint16(LCALL), + /*9937*/ uint16(xReadCd), + /*9938*/ uint16(xArgPtr16colon16), + /*9939*/ uint16(xMatch), + /*9940*/ uint16(xSetOp), uint16(LCALL), + /*9942*/ uint16(xReadCp), + /*9943*/ uint16(xArgPtr16colon32), + /*9944*/ uint16(xMatch), + /*9945*/ uint16(xSetOp), uint16(FWAIT), + /*9947*/ uint16(xMatch), + /*9948*/ uint16(xCondIs64), 9951, 9961, + /*9951*/ uint16(xCondDataSize), 9955, 9958, 0, + /*9955*/ uint16(xSetOp), uint16(PUSHF), + /*9957*/ uint16(xMatch), + /*9958*/ uint16(xSetOp), uint16(PUSHFD), + /*9960*/ uint16(xMatch), + /*9961*/ uint16(xCondDataSize), 9955, 9965, 9968, + /*9965*/ uint16(xSetOp), uint16(PUSHFQ), + /*9967*/ uint16(xMatch), + /*9968*/ uint16(xSetOp), uint16(PUSHFQ), + /*9970*/ uint16(xMatch), + /*9971*/ uint16(xCondIs64), 9974, 9984, + /*9974*/ uint16(xCondDataSize), 9978, 9981, 0, + /*9978*/ uint16(xSetOp), uint16(POPF), + /*9980*/ uint16(xMatch), + /*9981*/ uint16(xSetOp), uint16(POPFD), + /*9983*/ uint16(xMatch), + /*9984*/ uint16(xCondDataSize), 9978, 9988, 9991, + /*9988*/ uint16(xSetOp), uint16(POPFQ), + /*9990*/ uint16(xMatch), + /*9991*/ uint16(xSetOp), uint16(POPFQ), + /*9993*/ uint16(xMatch), + /*9994*/ uint16(xSetOp), uint16(SAHF), + /*9996*/ uint16(xMatch), + /*9997*/ uint16(xSetOp), uint16(LAHF), + /*9999*/ uint16(xMatch), + /*10000*/ uint16(xCondIs64), 10003, 10009, + /*10003*/ uint16(xSetOp), uint16(MOV), + /*10005*/ uint16(xReadCm), + /*10006*/ uint16(xArgAL), + /*10007*/ uint16(xArgMoffs8), + /*10008*/ uint16(xMatch), + /*10009*/ uint16(xCondDataSize), 10003, 10003, 10013, + /*10013*/ uint16(xSetOp), uint16(MOV), + /*10015*/ uint16(xReadCm), + /*10016*/ uint16(xArgAL), + /*10017*/ uint16(xArgMoffs8), + /*10018*/ uint16(xMatch), + /*10019*/ uint16(xCondDataSize), 10023, 10029, 10035, + /*10023*/ uint16(xSetOp), uint16(MOV), + /*10025*/ uint16(xReadCm), + /*10026*/ uint16(xArgAX), + /*10027*/ uint16(xArgMoffs16), + /*10028*/ uint16(xMatch), + /*10029*/ uint16(xSetOp), uint16(MOV), + /*10031*/ uint16(xReadCm), + /*10032*/ uint16(xArgEAX), + /*10033*/ uint16(xArgMoffs32), + /*10034*/ uint16(xMatch), + /*10035*/ uint16(xSetOp), uint16(MOV), + /*10037*/ uint16(xReadCm), + /*10038*/ uint16(xArgRAX), + /*10039*/ uint16(xArgMoffs64), + /*10040*/ uint16(xMatch), + /*10041*/ uint16(xCondIs64), 10044, 10050, + /*10044*/ uint16(xSetOp), uint16(MOV), + /*10046*/ uint16(xReadCm), + /*10047*/ uint16(xArgMoffs8), + /*10048*/ uint16(xArgAL), + /*10049*/ uint16(xMatch), + /*10050*/ uint16(xCondDataSize), 10044, 10044, 10054, + /*10054*/ uint16(xSetOp), uint16(MOV), + /*10056*/ uint16(xReadCm), + /*10057*/ uint16(xArgMoffs8), + /*10058*/ uint16(xArgAL), + /*10059*/ uint16(xMatch), + /*10060*/ uint16(xCondDataSize), 10064, 10070, 10076, + /*10064*/ uint16(xSetOp), uint16(MOV), + /*10066*/ uint16(xReadCm), + /*10067*/ uint16(xArgMoffs16), + /*10068*/ uint16(xArgAX), + /*10069*/ uint16(xMatch), + /*10070*/ uint16(xSetOp), uint16(MOV), + /*10072*/ uint16(xReadCm), + /*10073*/ uint16(xArgMoffs32), + /*10074*/ uint16(xArgEAX), + /*10075*/ uint16(xMatch), + /*10076*/ uint16(xSetOp), uint16(MOV), + /*10078*/ uint16(xReadCm), + /*10079*/ uint16(xArgMoffs64), + /*10080*/ uint16(xArgRAX), + /*10081*/ uint16(xMatch), + /*10082*/ uint16(xSetOp), uint16(MOVSB), + /*10084*/ uint16(xMatch), + /*10085*/ uint16(xCondIs64), 10088, 10098, + /*10088*/ uint16(xCondDataSize), 10092, 10095, 0, + /*10092*/ uint16(xSetOp), uint16(MOVSW), + /*10094*/ uint16(xMatch), + /*10095*/ uint16(xSetOp), uint16(MOVSD), + /*10097*/ uint16(xMatch), + /*10098*/ uint16(xCondDataSize), 10092, 10095, 10102, + /*10102*/ uint16(xSetOp), uint16(MOVSQ), + /*10104*/ uint16(xMatch), + /*10105*/ uint16(xSetOp), uint16(CMPSB), + /*10107*/ uint16(xMatch), + /*10108*/ uint16(xCondIs64), 10111, 10121, + /*10111*/ uint16(xCondDataSize), 10115, 10118, 0, + /*10115*/ uint16(xSetOp), uint16(CMPSW), + /*10117*/ uint16(xMatch), + /*10118*/ uint16(xSetOp), uint16(CMPSD), + /*10120*/ uint16(xMatch), + /*10121*/ uint16(xCondDataSize), 10115, 10118, 10125, + /*10125*/ uint16(xSetOp), uint16(CMPSQ), + /*10127*/ uint16(xMatch), + /*10128*/ uint16(xSetOp), uint16(TEST), + /*10130*/ uint16(xReadIb), + /*10131*/ uint16(xArgAL), + /*10132*/ uint16(xArgImm8u), + /*10133*/ uint16(xMatch), + /*10134*/ uint16(xCondIs64), 10137, 10153, + /*10137*/ uint16(xCondDataSize), 10141, 10147, 0, + /*10141*/ uint16(xSetOp), uint16(TEST), + /*10143*/ uint16(xReadIw), + /*10144*/ uint16(xArgAX), + /*10145*/ uint16(xArgImm16), + /*10146*/ uint16(xMatch), + /*10147*/ uint16(xSetOp), uint16(TEST), + /*10149*/ uint16(xReadId), + /*10150*/ uint16(xArgEAX), + /*10151*/ uint16(xArgImm32), + /*10152*/ uint16(xMatch), + /*10153*/ uint16(xCondDataSize), 10141, 10147, 10157, + /*10157*/ uint16(xSetOp), uint16(TEST), + /*10159*/ uint16(xReadId), + /*10160*/ uint16(xArgRAX), + /*10161*/ uint16(xArgImm32), + /*10162*/ uint16(xMatch), + /*10163*/ uint16(xSetOp), uint16(STOSB), + /*10165*/ uint16(xMatch), + /*10166*/ uint16(xCondIs64), 10169, 10179, + /*10169*/ uint16(xCondDataSize), 10173, 10176, 0, + /*10173*/ uint16(xSetOp), uint16(STOSW), + /*10175*/ uint16(xMatch), + /*10176*/ uint16(xSetOp), uint16(STOSD), + /*10178*/ uint16(xMatch), + /*10179*/ uint16(xCondDataSize), 10173, 10176, 10183, + /*10183*/ uint16(xSetOp), uint16(STOSQ), + /*10185*/ uint16(xMatch), + /*10186*/ uint16(xSetOp), uint16(LODSB), + /*10188*/ uint16(xMatch), + /*10189*/ uint16(xCondIs64), 10192, 10202, + /*10192*/ uint16(xCondDataSize), 10196, 10199, 0, + /*10196*/ uint16(xSetOp), uint16(LODSW), + /*10198*/ uint16(xMatch), + /*10199*/ uint16(xSetOp), uint16(LODSD), + /*10201*/ uint16(xMatch), + /*10202*/ uint16(xCondDataSize), 10196, 10199, 10206, + /*10206*/ uint16(xSetOp), uint16(LODSQ), + /*10208*/ uint16(xMatch), + /*10209*/ uint16(xSetOp), uint16(SCASB), + /*10211*/ uint16(xMatch), + /*10212*/ uint16(xCondIs64), 10215, 10225, + /*10215*/ uint16(xCondDataSize), 10219, 10222, 0, + /*10219*/ uint16(xSetOp), uint16(SCASW), + /*10221*/ uint16(xMatch), + /*10222*/ uint16(xSetOp), uint16(SCASD), + /*10224*/ uint16(xMatch), + /*10225*/ uint16(xCondDataSize), 10219, 10222, 10229, + /*10229*/ uint16(xSetOp), uint16(SCASQ), + /*10231*/ uint16(xMatch), + /*10232*/ uint16(xSetOp), uint16(MOV), + /*10234*/ uint16(xReadIb), + /*10235*/ uint16(xArgR8op), + /*10236*/ uint16(xArgImm8u), + /*10237*/ uint16(xMatch), + /*10238*/ uint16(xCondIs64), 10241, 10257, + /*10241*/ uint16(xCondDataSize), 10245, 10251, 0, + /*10245*/ uint16(xSetOp), uint16(MOV), + /*10247*/ uint16(xReadIw), + /*10248*/ uint16(xArgR16op), + /*10249*/ uint16(xArgImm16), + /*10250*/ uint16(xMatch), + /*10251*/ uint16(xSetOp), uint16(MOV), + /*10253*/ uint16(xReadId), + /*10254*/ uint16(xArgR32op), + /*10255*/ uint16(xArgImm32), + /*10256*/ uint16(xMatch), + /*10257*/ uint16(xCondDataSize), 10245, 10251, 10261, + /*10261*/ uint16(xSetOp), uint16(MOV), + /*10263*/ uint16(xReadIo), + /*10264*/ uint16(xArgR64op), + /*10265*/ uint16(xArgImm64), + /*10266*/ uint16(xMatch), + /*10267*/ uint16(xCondSlashR), + 10276, // 0 + 10282, // 1 + 10288, // 2 + 10294, // 3 + 10300, // 4 + 10306, // 5 + 0, // 6 + 10312, // 7 + /*10276*/ uint16(xSetOp), uint16(ROL), + /*10278*/ uint16(xReadIb), + /*10279*/ uint16(xArgRM8), + /*10280*/ uint16(xArgImm8u), + /*10281*/ uint16(xMatch), + /*10282*/ uint16(xSetOp), uint16(ROR), + /*10284*/ uint16(xReadIb), + /*10285*/ uint16(xArgRM8), + /*10286*/ uint16(xArgImm8u), + /*10287*/ uint16(xMatch), + /*10288*/ uint16(xSetOp), uint16(RCL), + /*10290*/ uint16(xReadIb), + /*10291*/ uint16(xArgRM8), + /*10292*/ uint16(xArgImm8u), + /*10293*/ uint16(xMatch), + /*10294*/ uint16(xSetOp), uint16(RCR), + /*10296*/ uint16(xReadIb), + /*10297*/ uint16(xArgRM8), + /*10298*/ uint16(xArgImm8u), + /*10299*/ uint16(xMatch), + /*10300*/ uint16(xSetOp), uint16(SHL), + /*10302*/ uint16(xReadIb), + /*10303*/ uint16(xArgRM8), + /*10304*/ uint16(xArgImm8u), + /*10305*/ uint16(xMatch), + /*10306*/ uint16(xSetOp), uint16(SHR), + /*10308*/ uint16(xReadIb), + /*10309*/ uint16(xArgRM8), + /*10310*/ uint16(xArgImm8u), + /*10311*/ uint16(xMatch), + /*10312*/ uint16(xSetOp), uint16(SAR), + /*10314*/ uint16(xReadIb), + /*10315*/ uint16(xArgRM8), + /*10316*/ uint16(xArgImm8u), + /*10317*/ uint16(xMatch), + /*10318*/ uint16(xCondSlashR), + 10327, // 0 + 10349, // 1 + 10371, // 2 + 10400, // 3 + 10429, // 4 + 10458, // 5 + 0, // 6 + 10487, // 7 + /*10327*/ uint16(xCondDataSize), 10331, 10337, 10343, + /*10331*/ uint16(xSetOp), uint16(ROL), + /*10333*/ uint16(xReadIb), + /*10334*/ uint16(xArgRM16), + /*10335*/ uint16(xArgImm8u), + /*10336*/ uint16(xMatch), + /*10337*/ uint16(xSetOp), uint16(ROL), + /*10339*/ uint16(xReadIb), + /*10340*/ uint16(xArgRM32), + /*10341*/ uint16(xArgImm8u), + /*10342*/ uint16(xMatch), + /*10343*/ uint16(xSetOp), uint16(ROL), + /*10345*/ uint16(xReadIb), + /*10346*/ uint16(xArgRM64), + /*10347*/ uint16(xArgImm8u), + /*10348*/ uint16(xMatch), + /*10349*/ uint16(xCondDataSize), 10353, 10359, 10365, + /*10353*/ uint16(xSetOp), uint16(ROR), + /*10355*/ uint16(xReadIb), + /*10356*/ uint16(xArgRM16), + /*10357*/ uint16(xArgImm8u), + /*10358*/ uint16(xMatch), + /*10359*/ uint16(xSetOp), uint16(ROR), + /*10361*/ uint16(xReadIb), + /*10362*/ uint16(xArgRM32), + /*10363*/ uint16(xArgImm8u), + /*10364*/ uint16(xMatch), + /*10365*/ uint16(xSetOp), uint16(ROR), + /*10367*/ uint16(xReadIb), + /*10368*/ uint16(xArgRM64), + /*10369*/ uint16(xArgImm8u), + /*10370*/ uint16(xMatch), + /*10371*/ uint16(xCondIs64), 10374, 10390, + /*10374*/ uint16(xCondDataSize), 10378, 10384, 0, + /*10378*/ uint16(xSetOp), uint16(RCL), + /*10380*/ uint16(xReadIb), + /*10381*/ uint16(xArgRM16), + /*10382*/ uint16(xArgImm8u), + /*10383*/ uint16(xMatch), + /*10384*/ uint16(xSetOp), uint16(RCL), + /*10386*/ uint16(xReadIb), + /*10387*/ uint16(xArgRM32), + /*10388*/ uint16(xArgImm8u), + /*10389*/ uint16(xMatch), + /*10390*/ uint16(xCondDataSize), 10378, 10384, 10394, + /*10394*/ uint16(xSetOp), uint16(RCL), + /*10396*/ uint16(xReadIb), + /*10397*/ uint16(xArgRM64), + /*10398*/ uint16(xArgImm8u), + /*10399*/ uint16(xMatch), + /*10400*/ uint16(xCondIs64), 10403, 10419, + /*10403*/ uint16(xCondDataSize), 10407, 10413, 0, + /*10407*/ uint16(xSetOp), uint16(RCR), + /*10409*/ uint16(xReadIb), + /*10410*/ uint16(xArgRM16), + /*10411*/ uint16(xArgImm8u), + /*10412*/ uint16(xMatch), + /*10413*/ uint16(xSetOp), uint16(RCR), + /*10415*/ uint16(xReadIb), + /*10416*/ uint16(xArgRM32), + /*10417*/ uint16(xArgImm8u), + /*10418*/ uint16(xMatch), + /*10419*/ uint16(xCondDataSize), 10407, 10413, 10423, + /*10423*/ uint16(xSetOp), uint16(RCR), + /*10425*/ uint16(xReadIb), + /*10426*/ uint16(xArgRM64), + /*10427*/ uint16(xArgImm8u), + /*10428*/ uint16(xMatch), + /*10429*/ uint16(xCondIs64), 10432, 10448, + /*10432*/ uint16(xCondDataSize), 10436, 10442, 0, + /*10436*/ uint16(xSetOp), uint16(SHL), + /*10438*/ uint16(xReadIb), + /*10439*/ uint16(xArgRM16), + /*10440*/ uint16(xArgImm8u), + /*10441*/ uint16(xMatch), + /*10442*/ uint16(xSetOp), uint16(SHL), + /*10444*/ uint16(xReadIb), + /*10445*/ uint16(xArgRM32), + /*10446*/ uint16(xArgImm8u), + /*10447*/ uint16(xMatch), + /*10448*/ uint16(xCondDataSize), 10436, 10442, 10452, + /*10452*/ uint16(xSetOp), uint16(SHL), + /*10454*/ uint16(xReadIb), + /*10455*/ uint16(xArgRM64), + /*10456*/ uint16(xArgImm8u), + /*10457*/ uint16(xMatch), + /*10458*/ uint16(xCondIs64), 10461, 10477, + /*10461*/ uint16(xCondDataSize), 10465, 10471, 0, + /*10465*/ uint16(xSetOp), uint16(SHR), + /*10467*/ uint16(xReadIb), + /*10468*/ uint16(xArgRM16), + /*10469*/ uint16(xArgImm8u), + /*10470*/ uint16(xMatch), + /*10471*/ uint16(xSetOp), uint16(SHR), + /*10473*/ uint16(xReadIb), + /*10474*/ uint16(xArgRM32), + /*10475*/ uint16(xArgImm8u), + /*10476*/ uint16(xMatch), + /*10477*/ uint16(xCondDataSize), 10465, 10471, 10481, + /*10481*/ uint16(xSetOp), uint16(SHR), + /*10483*/ uint16(xReadIb), + /*10484*/ uint16(xArgRM64), + /*10485*/ uint16(xArgImm8u), + /*10486*/ uint16(xMatch), + /*10487*/ uint16(xCondIs64), 10490, 10506, + /*10490*/ uint16(xCondDataSize), 10494, 10500, 0, + /*10494*/ uint16(xSetOp), uint16(SAR), + /*10496*/ uint16(xReadIb), + /*10497*/ uint16(xArgRM16), + /*10498*/ uint16(xArgImm8u), + /*10499*/ uint16(xMatch), + /*10500*/ uint16(xSetOp), uint16(SAR), + /*10502*/ uint16(xReadIb), + /*10503*/ uint16(xArgRM32), + /*10504*/ uint16(xArgImm8u), + /*10505*/ uint16(xMatch), + /*10506*/ uint16(xCondDataSize), 10494, 10500, 10510, + /*10510*/ uint16(xSetOp), uint16(SAR), + /*10512*/ uint16(xReadIb), + /*10513*/ uint16(xArgRM64), + /*10514*/ uint16(xArgImm8u), + /*10515*/ uint16(xMatch), + /*10516*/ uint16(xSetOp), uint16(RET), + /*10518*/ uint16(xReadIw), + /*10519*/ uint16(xArgImm16u), + /*10520*/ uint16(xMatch), + /*10521*/ uint16(xSetOp), uint16(RET), + /*10523*/ uint16(xMatch), + /*10524*/ uint16(xCondIs64), 10527, 0, + /*10527*/ uint16(xCondDataSize), 10531, 10537, 0, + /*10531*/ uint16(xSetOp), uint16(LES), + /*10533*/ uint16(xReadSlashR), + /*10534*/ uint16(xArgR16), + /*10535*/ uint16(xArgM16colon16), + /*10536*/ uint16(xMatch), + /*10537*/ uint16(xSetOp), uint16(LES), + /*10539*/ uint16(xReadSlashR), + /*10540*/ uint16(xArgR32), + /*10541*/ uint16(xArgM16colon32), + /*10542*/ uint16(xMatch), + /*10543*/ uint16(xCondIs64), 10546, 0, + /*10546*/ uint16(xCondDataSize), 10550, 10556, 0, + /*10550*/ uint16(xSetOp), uint16(LDS), + /*10552*/ uint16(xReadSlashR), + /*10553*/ uint16(xArgR16), + /*10554*/ uint16(xArgM16colon16), + /*10555*/ uint16(xMatch), + /*10556*/ uint16(xSetOp), uint16(LDS), + /*10558*/ uint16(xReadSlashR), + /*10559*/ uint16(xArgR32), + /*10560*/ uint16(xArgM16colon32), + /*10561*/ uint16(xMatch), + /*10562*/ uint16(xCondByte), 1, + 0xF8, 10581, + /*10566*/ uint16(xCondSlashR), + 10575, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*10575*/ uint16(xSetOp), uint16(MOV), + /*10577*/ uint16(xReadIb), + /*10578*/ uint16(xArgRM8), + /*10579*/ uint16(xArgImm8u), + /*10580*/ uint16(xMatch), + /*10581*/ uint16(xSetOp), uint16(XABORT), + /*10583*/ uint16(xReadIb), + /*10584*/ uint16(xArgImm8u), + /*10585*/ uint16(xMatch), + /*10586*/ uint16(xCondByte), 1, + 0xF8, 10628, + /*10590*/ uint16(xCondSlashR), + 10599, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*10599*/ uint16(xCondIs64), 10602, 10618, + /*10602*/ uint16(xCondDataSize), 10606, 10612, 0, + /*10606*/ uint16(xSetOp), uint16(MOV), + /*10608*/ uint16(xReadIw), + /*10609*/ uint16(xArgRM16), + /*10610*/ uint16(xArgImm16), + /*10611*/ uint16(xMatch), + /*10612*/ uint16(xSetOp), uint16(MOV), + /*10614*/ uint16(xReadId), + /*10615*/ uint16(xArgRM32), + /*10616*/ uint16(xArgImm32), + /*10617*/ uint16(xMatch), + /*10618*/ uint16(xCondDataSize), 10606, 10612, 10622, + /*10622*/ uint16(xSetOp), uint16(MOV), + /*10624*/ uint16(xReadId), + /*10625*/ uint16(xArgRM64), + /*10626*/ uint16(xArgImm32), + /*10627*/ uint16(xMatch), + /*10628*/ uint16(xCondDataSize), 10632, 10637, 10642, + /*10632*/ uint16(xSetOp), uint16(XBEGIN), + /*10634*/ uint16(xReadCw), + /*10635*/ uint16(xArgRel16), + /*10636*/ uint16(xMatch), + /*10637*/ uint16(xSetOp), uint16(XBEGIN), + /*10639*/ uint16(xReadCd), + /*10640*/ uint16(xArgRel32), + /*10641*/ uint16(xMatch), + /*10642*/ uint16(xSetOp), uint16(XBEGIN), + /*10644*/ uint16(xReadCd), + /*10645*/ uint16(xArgRel32), + /*10646*/ uint16(xMatch), + /*10647*/ uint16(xSetOp), uint16(ENTER), + /*10649*/ uint16(xReadIw), + /*10650*/ uint16(xReadIb), + /*10651*/ uint16(xArgImm16u), + /*10652*/ uint16(xArgImm8u), + /*10653*/ uint16(xMatch), + /*10654*/ uint16(xCondIs64), 10657, 10667, + /*10657*/ uint16(xCondDataSize), 10661, 10664, 0, + /*10661*/ uint16(xSetOp), uint16(LEAVE), + /*10663*/ uint16(xMatch), + /*10664*/ uint16(xSetOp), uint16(LEAVE), + /*10666*/ uint16(xMatch), + /*10667*/ uint16(xCondDataSize), 10661, 10671, 10674, + /*10671*/ uint16(xSetOp), uint16(LEAVE), + /*10673*/ uint16(xMatch), + /*10674*/ uint16(xSetOp), uint16(LEAVE), + /*10676*/ uint16(xMatch), + /*10677*/ uint16(xSetOp), uint16(LRET), + /*10679*/ uint16(xReadIw), + /*10680*/ uint16(xArgImm16u), + /*10681*/ uint16(xMatch), + /*10682*/ uint16(xSetOp), uint16(LRET), + /*10684*/ uint16(xMatch), + /*10685*/ uint16(xSetOp), uint16(INT), + /*10687*/ uint16(xArg3), + /*10688*/ uint16(xMatch), + /*10689*/ uint16(xSetOp), uint16(INT), + /*10691*/ uint16(xReadIb), + /*10692*/ uint16(xArgImm8u), + /*10693*/ uint16(xMatch), + /*10694*/ uint16(xCondIs64), 10697, 0, + /*10697*/ uint16(xSetOp), uint16(INTO), + /*10699*/ uint16(xMatch), + /*10700*/ uint16(xCondIs64), 10703, 10713, + /*10703*/ uint16(xCondDataSize), 10707, 10710, 0, + /*10707*/ uint16(xSetOp), uint16(IRET), + /*10709*/ uint16(xMatch), + /*10710*/ uint16(xSetOp), uint16(IRETD), + /*10712*/ uint16(xMatch), + /*10713*/ uint16(xCondDataSize), 10707, 10710, 10717, + /*10717*/ uint16(xSetOp), uint16(IRETQ), + /*10719*/ uint16(xMatch), + /*10720*/ uint16(xCondSlashR), + 10729, // 0 + 10734, // 1 + 10739, // 2 + 10744, // 3 + 10749, // 4 + 10754, // 5 + 0, // 6 + 10759, // 7 + /*10729*/ uint16(xSetOp), uint16(ROL), + /*10731*/ uint16(xArgRM8), + /*10732*/ uint16(xArg1), + /*10733*/ uint16(xMatch), + /*10734*/ uint16(xSetOp), uint16(ROR), + /*10736*/ uint16(xArgRM8), + /*10737*/ uint16(xArg1), + /*10738*/ uint16(xMatch), + /*10739*/ uint16(xSetOp), uint16(RCL), + /*10741*/ uint16(xArgRM8), + /*10742*/ uint16(xArg1), + /*10743*/ uint16(xMatch), + /*10744*/ uint16(xSetOp), uint16(RCR), + /*10746*/ uint16(xArgRM8), + /*10747*/ uint16(xArg1), + /*10748*/ uint16(xMatch), + /*10749*/ uint16(xSetOp), uint16(SHL), + /*10751*/ uint16(xArgRM8), + /*10752*/ uint16(xArg1), + /*10753*/ uint16(xMatch), + /*10754*/ uint16(xSetOp), uint16(SHR), + /*10756*/ uint16(xArgRM8), + /*10757*/ uint16(xArg1), + /*10758*/ uint16(xMatch), + /*10759*/ uint16(xSetOp), uint16(SAR), + /*10761*/ uint16(xArgRM8), + /*10762*/ uint16(xArg1), + /*10763*/ uint16(xMatch), + /*10764*/ uint16(xCondSlashR), + 10773, // 0 + 10799, // 1 + 10825, // 2 + 10851, // 3 + 10877, // 4 + 10903, // 5 + 0, // 6 + 10929, // 7 + /*10773*/ uint16(xCondIs64), 10776, 10790, + /*10776*/ uint16(xCondDataSize), 10780, 10785, 0, + /*10780*/ uint16(xSetOp), uint16(ROL), + /*10782*/ uint16(xArgRM16), + /*10783*/ uint16(xArg1), + /*10784*/ uint16(xMatch), + /*10785*/ uint16(xSetOp), uint16(ROL), + /*10787*/ uint16(xArgRM32), + /*10788*/ uint16(xArg1), + /*10789*/ uint16(xMatch), + /*10790*/ uint16(xCondDataSize), 10780, 10785, 10794, + /*10794*/ uint16(xSetOp), uint16(ROL), + /*10796*/ uint16(xArgRM64), + /*10797*/ uint16(xArg1), + /*10798*/ uint16(xMatch), + /*10799*/ uint16(xCondIs64), 10802, 10816, + /*10802*/ uint16(xCondDataSize), 10806, 10811, 0, + /*10806*/ uint16(xSetOp), uint16(ROR), + /*10808*/ uint16(xArgRM16), + /*10809*/ uint16(xArg1), + /*10810*/ uint16(xMatch), + /*10811*/ uint16(xSetOp), uint16(ROR), + /*10813*/ uint16(xArgRM32), + /*10814*/ uint16(xArg1), + /*10815*/ uint16(xMatch), + /*10816*/ uint16(xCondDataSize), 10806, 10811, 10820, + /*10820*/ uint16(xSetOp), uint16(ROR), + /*10822*/ uint16(xArgRM64), + /*10823*/ uint16(xArg1), + /*10824*/ uint16(xMatch), + /*10825*/ uint16(xCondIs64), 10828, 10842, + /*10828*/ uint16(xCondDataSize), 10832, 10837, 0, + /*10832*/ uint16(xSetOp), uint16(RCL), + /*10834*/ uint16(xArgRM16), + /*10835*/ uint16(xArg1), + /*10836*/ uint16(xMatch), + /*10837*/ uint16(xSetOp), uint16(RCL), + /*10839*/ uint16(xArgRM32), + /*10840*/ uint16(xArg1), + /*10841*/ uint16(xMatch), + /*10842*/ uint16(xCondDataSize), 10832, 10837, 10846, + /*10846*/ uint16(xSetOp), uint16(RCL), + /*10848*/ uint16(xArgRM64), + /*10849*/ uint16(xArg1), + /*10850*/ uint16(xMatch), + /*10851*/ uint16(xCondIs64), 10854, 10868, + /*10854*/ uint16(xCondDataSize), 10858, 10863, 0, + /*10858*/ uint16(xSetOp), uint16(RCR), + /*10860*/ uint16(xArgRM16), + /*10861*/ uint16(xArg1), + /*10862*/ uint16(xMatch), + /*10863*/ uint16(xSetOp), uint16(RCR), + /*10865*/ uint16(xArgRM32), + /*10866*/ uint16(xArg1), + /*10867*/ uint16(xMatch), + /*10868*/ uint16(xCondDataSize), 10858, 10863, 10872, + /*10872*/ uint16(xSetOp), uint16(RCR), + /*10874*/ uint16(xArgRM64), + /*10875*/ uint16(xArg1), + /*10876*/ uint16(xMatch), + /*10877*/ uint16(xCondIs64), 10880, 10894, + /*10880*/ uint16(xCondDataSize), 10884, 10889, 0, + /*10884*/ uint16(xSetOp), uint16(SHL), + /*10886*/ uint16(xArgRM16), + /*10887*/ uint16(xArg1), + /*10888*/ uint16(xMatch), + /*10889*/ uint16(xSetOp), uint16(SHL), + /*10891*/ uint16(xArgRM32), + /*10892*/ uint16(xArg1), + /*10893*/ uint16(xMatch), + /*10894*/ uint16(xCondDataSize), 10884, 10889, 10898, + /*10898*/ uint16(xSetOp), uint16(SHL), + /*10900*/ uint16(xArgRM64), + /*10901*/ uint16(xArg1), + /*10902*/ uint16(xMatch), + /*10903*/ uint16(xCondIs64), 10906, 10920, + /*10906*/ uint16(xCondDataSize), 10910, 10915, 0, + /*10910*/ uint16(xSetOp), uint16(SHR), + /*10912*/ uint16(xArgRM16), + /*10913*/ uint16(xArg1), + /*10914*/ uint16(xMatch), + /*10915*/ uint16(xSetOp), uint16(SHR), + /*10917*/ uint16(xArgRM32), + /*10918*/ uint16(xArg1), + /*10919*/ uint16(xMatch), + /*10920*/ uint16(xCondDataSize), 10910, 10915, 10924, + /*10924*/ uint16(xSetOp), uint16(SHR), + /*10926*/ uint16(xArgRM64), + /*10927*/ uint16(xArg1), + /*10928*/ uint16(xMatch), + /*10929*/ uint16(xCondIs64), 10932, 10946, + /*10932*/ uint16(xCondDataSize), 10936, 10941, 0, + /*10936*/ uint16(xSetOp), uint16(SAR), + /*10938*/ uint16(xArgRM16), + /*10939*/ uint16(xArg1), + /*10940*/ uint16(xMatch), + /*10941*/ uint16(xSetOp), uint16(SAR), + /*10943*/ uint16(xArgRM32), + /*10944*/ uint16(xArg1), + /*10945*/ uint16(xMatch), + /*10946*/ uint16(xCondDataSize), 10936, 10941, 10950, + /*10950*/ uint16(xSetOp), uint16(SAR), + /*10952*/ uint16(xArgRM64), + /*10953*/ uint16(xArg1), + /*10954*/ uint16(xMatch), + /*10955*/ uint16(xCondSlashR), + 10964, // 0 + 10969, // 1 + 10974, // 2 + 10979, // 3 + 10984, // 4 + 10989, // 5 + 0, // 6 + 10994, // 7 + /*10964*/ uint16(xSetOp), uint16(ROL), + /*10966*/ uint16(xArgRM8), + /*10967*/ uint16(xArgCL), + /*10968*/ uint16(xMatch), + /*10969*/ uint16(xSetOp), uint16(ROR), + /*10971*/ uint16(xArgRM8), + /*10972*/ uint16(xArgCL), + /*10973*/ uint16(xMatch), + /*10974*/ uint16(xSetOp), uint16(RCL), + /*10976*/ uint16(xArgRM8), + /*10977*/ uint16(xArgCL), + /*10978*/ uint16(xMatch), + /*10979*/ uint16(xSetOp), uint16(RCR), + /*10981*/ uint16(xArgRM8), + /*10982*/ uint16(xArgCL), + /*10983*/ uint16(xMatch), + /*10984*/ uint16(xSetOp), uint16(SHL), + /*10986*/ uint16(xArgRM8), + /*10987*/ uint16(xArgCL), + /*10988*/ uint16(xMatch), + /*10989*/ uint16(xSetOp), uint16(SHR), + /*10991*/ uint16(xArgRM8), + /*10992*/ uint16(xArgCL), + /*10993*/ uint16(xMatch), + /*10994*/ uint16(xSetOp), uint16(SAR), + /*10996*/ uint16(xArgRM8), + /*10997*/ uint16(xArgCL), + /*10998*/ uint16(xMatch), + /*10999*/ uint16(xCondSlashR), + 11008, // 0 + 11034, // 1 + 11060, // 2 + 11086, // 3 + 11112, // 4 + 11138, // 5 + 0, // 6 + 11164, // 7 + /*11008*/ uint16(xCondIs64), 11011, 11025, + /*11011*/ uint16(xCondDataSize), 11015, 11020, 0, + /*11015*/ uint16(xSetOp), uint16(ROL), + /*11017*/ uint16(xArgRM16), + /*11018*/ uint16(xArgCL), + /*11019*/ uint16(xMatch), + /*11020*/ uint16(xSetOp), uint16(ROL), + /*11022*/ uint16(xArgRM32), + /*11023*/ uint16(xArgCL), + /*11024*/ uint16(xMatch), + /*11025*/ uint16(xCondDataSize), 11015, 11020, 11029, + /*11029*/ uint16(xSetOp), uint16(ROL), + /*11031*/ uint16(xArgRM64), + /*11032*/ uint16(xArgCL), + /*11033*/ uint16(xMatch), + /*11034*/ uint16(xCondIs64), 11037, 11051, + /*11037*/ uint16(xCondDataSize), 11041, 11046, 0, + /*11041*/ uint16(xSetOp), uint16(ROR), + /*11043*/ uint16(xArgRM16), + /*11044*/ uint16(xArgCL), + /*11045*/ uint16(xMatch), + /*11046*/ uint16(xSetOp), uint16(ROR), + /*11048*/ uint16(xArgRM32), + /*11049*/ uint16(xArgCL), + /*11050*/ uint16(xMatch), + /*11051*/ uint16(xCondDataSize), 11041, 11046, 11055, + /*11055*/ uint16(xSetOp), uint16(ROR), + /*11057*/ uint16(xArgRM64), + /*11058*/ uint16(xArgCL), + /*11059*/ uint16(xMatch), + /*11060*/ uint16(xCondIs64), 11063, 11077, + /*11063*/ uint16(xCondDataSize), 11067, 11072, 0, + /*11067*/ uint16(xSetOp), uint16(RCL), + /*11069*/ uint16(xArgRM16), + /*11070*/ uint16(xArgCL), + /*11071*/ uint16(xMatch), + /*11072*/ uint16(xSetOp), uint16(RCL), + /*11074*/ uint16(xArgRM32), + /*11075*/ uint16(xArgCL), + /*11076*/ uint16(xMatch), + /*11077*/ uint16(xCondDataSize), 11067, 11072, 11081, + /*11081*/ uint16(xSetOp), uint16(RCL), + /*11083*/ uint16(xArgRM64), + /*11084*/ uint16(xArgCL), + /*11085*/ uint16(xMatch), + /*11086*/ uint16(xCondIs64), 11089, 11103, + /*11089*/ uint16(xCondDataSize), 11093, 11098, 0, + /*11093*/ uint16(xSetOp), uint16(RCR), + /*11095*/ uint16(xArgRM16), + /*11096*/ uint16(xArgCL), + /*11097*/ uint16(xMatch), + /*11098*/ uint16(xSetOp), uint16(RCR), + /*11100*/ uint16(xArgRM32), + /*11101*/ uint16(xArgCL), + /*11102*/ uint16(xMatch), + /*11103*/ uint16(xCondDataSize), 11093, 11098, 11107, + /*11107*/ uint16(xSetOp), uint16(RCR), + /*11109*/ uint16(xArgRM64), + /*11110*/ uint16(xArgCL), + /*11111*/ uint16(xMatch), + /*11112*/ uint16(xCondIs64), 11115, 11129, + /*11115*/ uint16(xCondDataSize), 11119, 11124, 0, + /*11119*/ uint16(xSetOp), uint16(SHL), + /*11121*/ uint16(xArgRM16), + /*11122*/ uint16(xArgCL), + /*11123*/ uint16(xMatch), + /*11124*/ uint16(xSetOp), uint16(SHL), + /*11126*/ uint16(xArgRM32), + /*11127*/ uint16(xArgCL), + /*11128*/ uint16(xMatch), + /*11129*/ uint16(xCondDataSize), 11119, 11124, 11133, + /*11133*/ uint16(xSetOp), uint16(SHL), + /*11135*/ uint16(xArgRM64), + /*11136*/ uint16(xArgCL), + /*11137*/ uint16(xMatch), + /*11138*/ uint16(xCondIs64), 11141, 11155, + /*11141*/ uint16(xCondDataSize), 11145, 11150, 0, + /*11145*/ uint16(xSetOp), uint16(SHR), + /*11147*/ uint16(xArgRM16), + /*11148*/ uint16(xArgCL), + /*11149*/ uint16(xMatch), + /*11150*/ uint16(xSetOp), uint16(SHR), + /*11152*/ uint16(xArgRM32), + /*11153*/ uint16(xArgCL), + /*11154*/ uint16(xMatch), + /*11155*/ uint16(xCondDataSize), 11145, 11150, 11159, + /*11159*/ uint16(xSetOp), uint16(SHR), + /*11161*/ uint16(xArgRM64), + /*11162*/ uint16(xArgCL), + /*11163*/ uint16(xMatch), + /*11164*/ uint16(xCondIs64), 11167, 11181, + /*11167*/ uint16(xCondDataSize), 11171, 11176, 0, + /*11171*/ uint16(xSetOp), uint16(SAR), + /*11173*/ uint16(xArgRM16), + /*11174*/ uint16(xArgCL), + /*11175*/ uint16(xMatch), + /*11176*/ uint16(xSetOp), uint16(SAR), + /*11178*/ uint16(xArgRM32), + /*11179*/ uint16(xArgCL), + /*11180*/ uint16(xMatch), + /*11181*/ uint16(xCondDataSize), 11171, 11176, 11185, + /*11185*/ uint16(xSetOp), uint16(SAR), + /*11187*/ uint16(xArgRM64), + /*11188*/ uint16(xArgCL), + /*11189*/ uint16(xMatch), + /*11190*/ uint16(xCondIs64), 11193, 0, + /*11193*/ uint16(xSetOp), uint16(AAM), + /*11195*/ uint16(xReadIb), + /*11196*/ uint16(xArgImm8u), + /*11197*/ uint16(xMatch), + /*11198*/ uint16(xCondIs64), 11201, 0, + /*11201*/ uint16(xSetOp), uint16(AAD), + /*11203*/ uint16(xReadIb), + /*11204*/ uint16(xArgImm8u), + /*11205*/ uint16(xMatch), + /*11206*/ uint16(xCondIs64), 11209, 11212, + /*11209*/ uint16(xSetOp), uint16(XLATB), + /*11211*/ uint16(xMatch), + /*11212*/ uint16(xCondDataSize), 11209, 11209, 11216, + /*11216*/ uint16(xSetOp), uint16(XLATB), + /*11218*/ uint16(xMatch), + /*11219*/ uint16(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(xCondSlashR), + 11358, // 0 + 11362, // 1 + 11366, // 2 + 11370, // 3 + 11374, // 4 + 11378, // 5 + 11382, // 6 + 11386, // 7 + /*11358*/ uint16(xSetOp), uint16(FADD), + /*11360*/ uint16(xArgM32fp), + /*11361*/ uint16(xMatch), + /*11362*/ uint16(xSetOp), uint16(FMUL), + /*11364*/ uint16(xArgM32fp), + /*11365*/ uint16(xMatch), + /*11366*/ uint16(xSetOp), uint16(FCOM), + /*11368*/ uint16(xArgM32fp), + /*11369*/ uint16(xMatch), + /*11370*/ uint16(xSetOp), uint16(FCOMP), + /*11372*/ uint16(xArgM32fp), + /*11373*/ uint16(xMatch), + /*11374*/ uint16(xSetOp), uint16(FSUB), + /*11376*/ uint16(xArgM32fp), + /*11377*/ uint16(xMatch), + /*11378*/ uint16(xSetOp), uint16(FSUBR), + /*11380*/ uint16(xArgM32fp), + /*11381*/ uint16(xMatch), + /*11382*/ uint16(xSetOp), uint16(FDIV), + /*11384*/ uint16(xArgM32fp), + /*11385*/ uint16(xMatch), + /*11386*/ uint16(xSetOp), uint16(FDIVR), + /*11388*/ uint16(xArgM32fp), + /*11389*/ uint16(xMatch), + /*11390*/ uint16(xSetOp), uint16(FADD), + /*11392*/ uint16(xArgST), + /*11393*/ uint16(xArgSTi), + /*11394*/ uint16(xMatch), + /*11395*/ uint16(xSetOp), uint16(FMUL), + /*11397*/ uint16(xArgST), + /*11398*/ uint16(xArgSTi), + /*11399*/ uint16(xMatch), + /*11400*/ uint16(xSetOp), uint16(FCOM), + /*11402*/ uint16(xArgSTi), + /*11403*/ uint16(xMatch), + /*11404*/ uint16(xSetOp), uint16(FCOMP), + /*11406*/ uint16(xArgSTi), + /*11407*/ uint16(xMatch), + /*11408*/ uint16(xSetOp), uint16(FSUB), + /*11410*/ uint16(xArgST), + /*11411*/ uint16(xArgSTi), + /*11412*/ uint16(xMatch), + /*11413*/ uint16(xSetOp), uint16(FSUBR), + /*11415*/ uint16(xArgST), + /*11416*/ uint16(xArgSTi), + /*11417*/ uint16(xMatch), + /*11418*/ uint16(xSetOp), uint16(FDIV), + /*11420*/ uint16(xArgST), + /*11421*/ uint16(xArgSTi), + /*11422*/ uint16(xMatch), + /*11423*/ uint16(xSetOp), uint16(FDIVR), + /*11425*/ uint16(xArgST), + /*11426*/ uint16(xArgSTi), + /*11427*/ uint16(xMatch), + /*11428*/ uint16(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(xCondSlashR), + 11523, // 0 + 0, // 1 + 11527, // 2 + 11531, // 3 + 11535, // 4 + 11539, // 5 + 11543, // 6 + 11547, // 7 + /*11523*/ uint16(xSetOp), uint16(FLD), + /*11525*/ uint16(xArgM32fp), + /*11526*/ uint16(xMatch), + /*11527*/ uint16(xSetOp), uint16(FST), + /*11529*/ uint16(xArgM32fp), + /*11530*/ uint16(xMatch), + /*11531*/ uint16(xSetOp), uint16(FSTP), + /*11533*/ uint16(xArgM32fp), + /*11534*/ uint16(xMatch), + /*11535*/ uint16(xSetOp), uint16(FLDENV), + /*11537*/ uint16(xArgM1428byte), + /*11538*/ uint16(xMatch), + /*11539*/ uint16(xSetOp), uint16(FLDCW), + /*11541*/ uint16(xArgM2byte), + /*11542*/ uint16(xMatch), + /*11543*/ uint16(xSetOp), uint16(FNSTENV), + /*11545*/ uint16(xArgM1428byte), + /*11546*/ uint16(xMatch), + /*11547*/ uint16(xSetOp), uint16(FNSTCW), + /*11549*/ uint16(xArgM2byte), + /*11550*/ uint16(xMatch), + /*11551*/ uint16(xSetOp), uint16(FLD), + /*11553*/ uint16(xArgSTi), + /*11554*/ uint16(xMatch), + /*11555*/ uint16(xSetOp), uint16(FXCH), + /*11557*/ uint16(xArgSTi), + /*11558*/ uint16(xMatch), + /*11559*/ uint16(xSetOp), uint16(FNOP), + /*11561*/ uint16(xMatch), + /*11562*/ uint16(xSetOp), uint16(FCHS), + /*11564*/ uint16(xMatch), + /*11565*/ uint16(xSetOp), uint16(FABS), + /*11567*/ uint16(xMatch), + /*11568*/ uint16(xSetOp), uint16(FTST), + /*11570*/ uint16(xMatch), + /*11571*/ uint16(xSetOp), uint16(FXAM), + /*11573*/ uint16(xMatch), + /*11574*/ uint16(xSetOp), uint16(FLD1), + /*11576*/ uint16(xMatch), + /*11577*/ uint16(xSetOp), uint16(FLDL2T), + /*11579*/ uint16(xMatch), + /*11580*/ uint16(xSetOp), uint16(FLDL2E), + /*11582*/ uint16(xMatch), + /*11583*/ uint16(xSetOp), uint16(FLDPI), + /*11585*/ uint16(xMatch), + /*11586*/ uint16(xSetOp), uint16(FLDLG2), + /*11588*/ uint16(xMatch), + /*11589*/ uint16(xSetOp), uint16(F2XM1), + /*11591*/ uint16(xMatch), + /*11592*/ uint16(xSetOp), uint16(FYL2X), + /*11594*/ uint16(xMatch), + /*11595*/ uint16(xSetOp), uint16(FPTAN), + /*11597*/ uint16(xMatch), + /*11598*/ uint16(xSetOp), uint16(FPATAN), + /*11600*/ uint16(xMatch), + /*11601*/ uint16(xSetOp), uint16(FXTRACT), + /*11603*/ uint16(xMatch), + /*11604*/ uint16(xSetOp), uint16(FPREM1), + /*11606*/ uint16(xMatch), + /*11607*/ uint16(xSetOp), uint16(FDECSTP), + /*11609*/ uint16(xMatch), + /*11610*/ uint16(xSetOp), uint16(FINCSTP), + /*11612*/ uint16(xMatch), + /*11613*/ uint16(xSetOp), uint16(FPREM), + /*11615*/ uint16(xMatch), + /*11616*/ uint16(xSetOp), uint16(FYL2XP1), + /*11618*/ uint16(xMatch), + /*11619*/ uint16(xSetOp), uint16(FSQRT), + /*11621*/ uint16(xMatch), + /*11622*/ uint16(xSetOp), uint16(FSINCOS), + /*11624*/ uint16(xMatch), + /*11625*/ uint16(xSetOp), uint16(FRNDINT), + /*11627*/ uint16(xMatch), + /*11628*/ uint16(xSetOp), uint16(FSCALE), + /*11630*/ uint16(xMatch), + /*11631*/ uint16(xSetOp), uint16(FSIN), + /*11633*/ uint16(xMatch), + /*11634*/ uint16(xSetOp), uint16(FCOS), + /*11636*/ uint16(xMatch), + /*11637*/ uint16(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(xCondSlashR), + 11714, // 0 + 11718, // 1 + 11722, // 2 + 11726, // 3 + 11730, // 4 + 11734, // 5 + 11738, // 6 + 11742, // 7 + /*11714*/ uint16(xSetOp), uint16(FIADD), + /*11716*/ uint16(xArgM32int), + /*11717*/ uint16(xMatch), + /*11718*/ uint16(xSetOp), uint16(FIMUL), + /*11720*/ uint16(xArgM32int), + /*11721*/ uint16(xMatch), + /*11722*/ uint16(xSetOp), uint16(FICOM), + /*11724*/ uint16(xArgM32int), + /*11725*/ uint16(xMatch), + /*11726*/ uint16(xSetOp), uint16(FICOMP), + /*11728*/ uint16(xArgM32int), + /*11729*/ uint16(xMatch), + /*11730*/ uint16(xSetOp), uint16(FISUB), + /*11732*/ uint16(xArgM32int), + /*11733*/ uint16(xMatch), + /*11734*/ uint16(xSetOp), uint16(FISUBR), + /*11736*/ uint16(xArgM32int), + /*11737*/ uint16(xMatch), + /*11738*/ uint16(xSetOp), uint16(FIDIV), + /*11740*/ uint16(xArgM32int), + /*11741*/ uint16(xMatch), + /*11742*/ uint16(xSetOp), uint16(FIDIVR), + /*11744*/ uint16(xArgM32int), + /*11745*/ uint16(xMatch), + /*11746*/ uint16(xSetOp), uint16(FCMOVB), + /*11748*/ uint16(xArgST), + /*11749*/ uint16(xArgSTi), + /*11750*/ uint16(xMatch), + /*11751*/ uint16(xSetOp), uint16(FCMOVE), + /*11753*/ uint16(xArgST), + /*11754*/ uint16(xArgSTi), + /*11755*/ uint16(xMatch), + /*11756*/ uint16(xSetOp), uint16(FCMOVBE), + /*11758*/ uint16(xArgST), + /*11759*/ uint16(xArgSTi), + /*11760*/ uint16(xMatch), + /*11761*/ uint16(xSetOp), uint16(FCMOVU), + /*11763*/ uint16(xArgST), + /*11764*/ uint16(xArgSTi), + /*11765*/ uint16(xMatch), + /*11766*/ uint16(xSetOp), uint16(FUCOMPP), + /*11768*/ uint16(xMatch), + /*11769*/ uint16(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(xCondSlashR), + 11880, // 0 + 11884, // 1 + 11888, // 2 + 11892, // 3 + 0, // 4 + 11896, // 5 + 0, // 6 + 11900, // 7 + /*11880*/ uint16(xSetOp), uint16(FILD), + /*11882*/ uint16(xArgM32int), + /*11883*/ uint16(xMatch), + /*11884*/ uint16(xSetOp), uint16(FISTTP), + /*11886*/ uint16(xArgM32int), + /*11887*/ uint16(xMatch), + /*11888*/ uint16(xSetOp), uint16(FIST), + /*11890*/ uint16(xArgM32int), + /*11891*/ uint16(xMatch), + /*11892*/ uint16(xSetOp), uint16(FISTP), + /*11894*/ uint16(xArgM32int), + /*11895*/ uint16(xMatch), + /*11896*/ uint16(xSetOp), uint16(FLD), + /*11898*/ uint16(xArgM80fp), + /*11899*/ uint16(xMatch), + /*11900*/ uint16(xSetOp), uint16(FSTP), + /*11902*/ uint16(xArgM80fp), + /*11903*/ uint16(xMatch), + /*11904*/ uint16(xSetOp), uint16(FCMOVNB), + /*11906*/ uint16(xArgST), + /*11907*/ uint16(xArgSTi), + /*11908*/ uint16(xMatch), + /*11909*/ uint16(xSetOp), uint16(FCMOVNE), + /*11911*/ uint16(xArgST), + /*11912*/ uint16(xArgSTi), + /*11913*/ uint16(xMatch), + /*11914*/ uint16(xSetOp), uint16(FCMOVNBE), + /*11916*/ uint16(xArgST), + /*11917*/ uint16(xArgSTi), + /*11918*/ uint16(xMatch), + /*11919*/ uint16(xSetOp), uint16(FCMOVNU), + /*11921*/ uint16(xArgST), + /*11922*/ uint16(xArgSTi), + /*11923*/ uint16(xMatch), + /*11924*/ uint16(xSetOp), uint16(FNCLEX), + /*11926*/ uint16(xMatch), + /*11927*/ uint16(xSetOp), uint16(FNINIT), + /*11929*/ uint16(xMatch), + /*11930*/ uint16(xSetOp), uint16(FUCOMI), + /*11932*/ uint16(xArgST), + /*11933*/ uint16(xArgSTi), + /*11934*/ uint16(xMatch), + /*11935*/ uint16(xSetOp), uint16(FCOMI), + /*11937*/ uint16(xArgST), + /*11938*/ uint16(xArgSTi), + /*11939*/ uint16(xMatch), + /*11940*/ uint16(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(xCondSlashR), + 12047, // 0 + 12051, // 1 + 12055, // 2 + 12059, // 3 + 12063, // 4 + 12067, // 5 + 12071, // 6 + 12075, // 7 + /*12047*/ uint16(xSetOp), uint16(FADD), + /*12049*/ uint16(xArgM64fp), + /*12050*/ uint16(xMatch), + /*12051*/ uint16(xSetOp), uint16(FMUL), + /*12053*/ uint16(xArgM64fp), + /*12054*/ uint16(xMatch), + /*12055*/ uint16(xSetOp), uint16(FCOM), + /*12057*/ uint16(xArgM64fp), + /*12058*/ uint16(xMatch), + /*12059*/ uint16(xSetOp), uint16(FCOMP), + /*12061*/ uint16(xArgM64fp), + /*12062*/ uint16(xMatch), + /*12063*/ uint16(xSetOp), uint16(FSUB), + /*12065*/ uint16(xArgM64fp), + /*12066*/ uint16(xMatch), + /*12067*/ uint16(xSetOp), uint16(FSUBR), + /*12069*/ uint16(xArgM64fp), + /*12070*/ uint16(xMatch), + /*12071*/ uint16(xSetOp), uint16(FDIV), + /*12073*/ uint16(xArgM64fp), + /*12074*/ uint16(xMatch), + /*12075*/ uint16(xSetOp), uint16(FDIVR), + /*12077*/ uint16(xArgM64fp), + /*12078*/ uint16(xMatch), + /*12079*/ uint16(xSetOp), uint16(FADD), + /*12081*/ uint16(xArgSTi), + /*12082*/ uint16(xArgST), + /*12083*/ uint16(xMatch), + /*12084*/ uint16(xSetOp), uint16(FMUL), + /*12086*/ uint16(xArgSTi), + /*12087*/ uint16(xArgST), + /*12088*/ uint16(xMatch), + /*12089*/ uint16(xSetOp), uint16(FSUBR), + /*12091*/ uint16(xArgSTi), + /*12092*/ uint16(xArgST), + /*12093*/ uint16(xMatch), + /*12094*/ uint16(xSetOp), uint16(FSUB), + /*12096*/ uint16(xArgSTi), + /*12097*/ uint16(xArgST), + /*12098*/ uint16(xMatch), + /*12099*/ uint16(xSetOp), uint16(FDIVR), + /*12101*/ uint16(xArgSTi), + /*12102*/ uint16(xArgST), + /*12103*/ uint16(xMatch), + /*12104*/ uint16(xSetOp), uint16(FDIV), + /*12106*/ uint16(xArgSTi), + /*12107*/ uint16(xArgST), + /*12108*/ uint16(xMatch), + /*12109*/ uint16(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(xCondSlashR), + 12200, // 0 + 12204, // 1 + 12208, // 2 + 12212, // 3 + 12216, // 4 + 0, // 5 + 12220, // 6 + 12224, // 7 + /*12200*/ uint16(xSetOp), uint16(FLD), + /*12202*/ uint16(xArgM64fp), + /*12203*/ uint16(xMatch), + /*12204*/ uint16(xSetOp), uint16(FISTTP), + /*12206*/ uint16(xArgM64int), + /*12207*/ uint16(xMatch), + /*12208*/ uint16(xSetOp), uint16(FST), + /*12210*/ uint16(xArgM64fp), + /*12211*/ uint16(xMatch), + /*12212*/ uint16(xSetOp), uint16(FSTP), + /*12214*/ uint16(xArgM64fp), + /*12215*/ uint16(xMatch), + /*12216*/ uint16(xSetOp), uint16(FRSTOR), + /*12218*/ uint16(xArgM94108byte), + /*12219*/ uint16(xMatch), + /*12220*/ uint16(xSetOp), uint16(FNSAVE), + /*12222*/ uint16(xArgM94108byte), + /*12223*/ uint16(xMatch), + /*12224*/ uint16(xSetOp), uint16(FNSTSW), + /*12226*/ uint16(xArgM2byte), + /*12227*/ uint16(xMatch), + /*12228*/ uint16(xSetOp), uint16(FFREE), + /*12230*/ uint16(xArgSTi), + /*12231*/ uint16(xMatch), + /*12232*/ uint16(xSetOp), uint16(FST), + /*12234*/ uint16(xArgSTi), + /*12235*/ uint16(xMatch), + /*12236*/ uint16(xSetOp), uint16(FSTP), + /*12238*/ uint16(xArgSTi), + /*12239*/ uint16(xMatch), + /*12240*/ uint16(xSetOp), uint16(FUCOM), + /*12242*/ uint16(xArgSTi), + /*12243*/ uint16(xMatch), + /*12244*/ uint16(xSetOp), uint16(FUCOMP), + /*12246*/ uint16(xArgSTi), + /*12247*/ uint16(xMatch), + /*12248*/ uint16(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(xCondSlashR), + 12357, // 0 + 12361, // 1 + 12365, // 2 + 12369, // 3 + 12373, // 4 + 12377, // 5 + 12381, // 6 + 12385, // 7 + /*12357*/ uint16(xSetOp), uint16(FIADD), + /*12359*/ uint16(xArgM16int), + /*12360*/ uint16(xMatch), + /*12361*/ uint16(xSetOp), uint16(FIMUL), + /*12363*/ uint16(xArgM16int), + /*12364*/ uint16(xMatch), + /*12365*/ uint16(xSetOp), uint16(FICOM), + /*12367*/ uint16(xArgM16int), + /*12368*/ uint16(xMatch), + /*12369*/ uint16(xSetOp), uint16(FICOMP), + /*12371*/ uint16(xArgM16int), + /*12372*/ uint16(xMatch), + /*12373*/ uint16(xSetOp), uint16(FISUB), + /*12375*/ uint16(xArgM16int), + /*12376*/ uint16(xMatch), + /*12377*/ uint16(xSetOp), uint16(FISUBR), + /*12379*/ uint16(xArgM16int), + /*12380*/ uint16(xMatch), + /*12381*/ uint16(xSetOp), uint16(FIDIV), + /*12383*/ uint16(xArgM16int), + /*12384*/ uint16(xMatch), + /*12385*/ uint16(xSetOp), uint16(FIDIVR), + /*12387*/ uint16(xArgM16int), + /*12388*/ uint16(xMatch), + /*12389*/ uint16(xSetOp), uint16(FADDP), + /*12391*/ uint16(xArgSTi), + /*12392*/ uint16(xArgST), + /*12393*/ uint16(xMatch), + /*12394*/ uint16(xSetOp), uint16(FMULP), + /*12396*/ uint16(xArgSTi), + /*12397*/ uint16(xArgST), + /*12398*/ uint16(xMatch), + /*12399*/ uint16(xSetOp), uint16(FCOMPP), + /*12401*/ uint16(xMatch), + /*12402*/ uint16(xSetOp), uint16(FSUBRP), + /*12404*/ uint16(xArgSTi), + /*12405*/ uint16(xArgST), + /*12406*/ uint16(xMatch), + /*12407*/ uint16(xSetOp), uint16(FSUBP), + /*12409*/ uint16(xArgSTi), + /*12410*/ uint16(xArgST), + /*12411*/ uint16(xMatch), + /*12412*/ uint16(xSetOp), uint16(FDIVRP), + /*12414*/ uint16(xArgSTi), + /*12415*/ uint16(xArgST), + /*12416*/ uint16(xMatch), + /*12417*/ uint16(xSetOp), uint16(FDIVP), + /*12419*/ uint16(xArgSTi), + /*12420*/ uint16(xArgST), + /*12421*/ uint16(xMatch), + /*12422*/ uint16(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(xCondSlashR), + 12483, // 0 + 12487, // 1 + 12491, // 2 + 12495, // 3 + 12499, // 4 + 12503, // 5 + 12507, // 6 + 12511, // 7 + /*12483*/ uint16(xSetOp), uint16(FILD), + /*12485*/ uint16(xArgM16int), + /*12486*/ uint16(xMatch), + /*12487*/ uint16(xSetOp), uint16(FISTTP), + /*12489*/ uint16(xArgM16int), + /*12490*/ uint16(xMatch), + /*12491*/ uint16(xSetOp), uint16(FIST), + /*12493*/ uint16(xArgM16int), + /*12494*/ uint16(xMatch), + /*12495*/ uint16(xSetOp), uint16(FISTP), + /*12497*/ uint16(xArgM16int), + /*12498*/ uint16(xMatch), + /*12499*/ uint16(xSetOp), uint16(FBLD), + /*12501*/ uint16(xArgM80dec), + /*12502*/ uint16(xMatch), + /*12503*/ uint16(xSetOp), uint16(FILD), + /*12505*/ uint16(xArgM64int), + /*12506*/ uint16(xMatch), + /*12507*/ uint16(xSetOp), uint16(FBSTP), + /*12509*/ uint16(xArgM80bcd), + /*12510*/ uint16(xMatch), + /*12511*/ uint16(xSetOp), uint16(FISTP), + /*12513*/ uint16(xArgM64int), + /*12514*/ uint16(xMatch), + /*12515*/ uint16(xSetOp), uint16(FFREEP), + /*12517*/ uint16(xArgSTi), + /*12518*/ uint16(xMatch), + /*12519*/ uint16(xSetOp), uint16(FNSTSW), + /*12521*/ uint16(xArgAX), + /*12522*/ uint16(xMatch), + /*12523*/ uint16(xSetOp), uint16(FUCOMIP), + /*12525*/ uint16(xArgST), + /*12526*/ uint16(xArgSTi), + /*12527*/ uint16(xMatch), + /*12528*/ uint16(xSetOp), uint16(FCOMIP), + /*12530*/ uint16(xArgST), + /*12531*/ uint16(xArgSTi), + /*12532*/ uint16(xMatch), + /*12533*/ uint16(xSetOp), uint16(LOOPNE), + /*12535*/ uint16(xReadCb), + /*12536*/ uint16(xArgRel8), + /*12537*/ uint16(xMatch), + /*12538*/ uint16(xSetOp), uint16(LOOPE), + /*12540*/ uint16(xReadCb), + /*12541*/ uint16(xArgRel8), + /*12542*/ uint16(xMatch), + /*12543*/ uint16(xSetOp), uint16(LOOP), + /*12545*/ uint16(xReadCb), + /*12546*/ uint16(xArgRel8), + /*12547*/ uint16(xMatch), + /*12548*/ uint16(xCondIs64), 12551, 12565, + /*12551*/ uint16(xCondAddrSize), 12555, 12560, 0, + /*12555*/ uint16(xSetOp), uint16(JCXZ), + /*12557*/ uint16(xReadCb), + /*12558*/ uint16(xArgRel8), + /*12559*/ uint16(xMatch), + /*12560*/ uint16(xSetOp), uint16(JECXZ), + /*12562*/ uint16(xReadCb), + /*12563*/ uint16(xArgRel8), + /*12564*/ uint16(xMatch), + /*12565*/ uint16(xCondAddrSize), 0, 12560, 12569, + /*12569*/ uint16(xSetOp), uint16(JRCXZ), + /*12571*/ uint16(xReadCb), + /*12572*/ uint16(xArgRel8), + /*12573*/ uint16(xMatch), + /*12574*/ uint16(xSetOp), uint16(IN), + /*12576*/ uint16(xReadIb), + /*12577*/ uint16(xArgAL), + /*12578*/ uint16(xArgImm8u), + /*12579*/ uint16(xMatch), + /*12580*/ uint16(xCondDataSize), 12584, 12590, 12596, + /*12584*/ uint16(xSetOp), uint16(IN), + /*12586*/ uint16(xReadIb), + /*12587*/ uint16(xArgAX), + /*12588*/ uint16(xArgImm8u), + /*12589*/ uint16(xMatch), + /*12590*/ uint16(xSetOp), uint16(IN), + /*12592*/ uint16(xReadIb), + /*12593*/ uint16(xArgEAX), + /*12594*/ uint16(xArgImm8u), + /*12595*/ uint16(xMatch), + /*12596*/ uint16(xSetOp), uint16(IN), + /*12598*/ uint16(xReadIb), + /*12599*/ uint16(xArgEAX), + /*12600*/ uint16(xArgImm8u), + /*12601*/ uint16(xMatch), + /*12602*/ uint16(xSetOp), uint16(OUT), + /*12604*/ uint16(xReadIb), + /*12605*/ uint16(xArgImm8u), + /*12606*/ uint16(xArgAL), + /*12607*/ uint16(xMatch), + /*12608*/ uint16(xCondDataSize), 12612, 12618, 12624, + /*12612*/ uint16(xSetOp), uint16(OUT), + /*12614*/ uint16(xReadIb), + /*12615*/ uint16(xArgImm8u), + /*12616*/ uint16(xArgAX), + /*12617*/ uint16(xMatch), + /*12618*/ uint16(xSetOp), uint16(OUT), + /*12620*/ uint16(xReadIb), + /*12621*/ uint16(xArgImm8u), + /*12622*/ uint16(xArgEAX), + /*12623*/ uint16(xMatch), + /*12624*/ uint16(xSetOp), uint16(OUT), + /*12626*/ uint16(xReadIb), + /*12627*/ uint16(xArgImm8u), + /*12628*/ uint16(xArgEAX), + /*12629*/ uint16(xMatch), + /*12630*/ uint16(xCondIs64), 12633, 12647, + /*12633*/ uint16(xCondDataSize), 12637, 12642, 0, + /*12637*/ uint16(xSetOp), uint16(CALL), + /*12639*/ uint16(xReadCw), + /*12640*/ uint16(xArgRel16), + /*12641*/ uint16(xMatch), + /*12642*/ uint16(xSetOp), uint16(CALL), + /*12644*/ uint16(xReadCd), + /*12645*/ uint16(xArgRel32), + /*12646*/ uint16(xMatch), + /*12647*/ uint16(xCondDataSize), 12651, 12642, 12656, + /*12651*/ uint16(xSetOp), uint16(CALL), + /*12653*/ uint16(xReadCd), + /*12654*/ uint16(xArgRel32), + /*12655*/ uint16(xMatch), + /*12656*/ uint16(xSetOp), uint16(CALL), + /*12658*/ uint16(xReadCd), + /*12659*/ uint16(xArgRel32), + /*12660*/ uint16(xMatch), + /*12661*/ uint16(xCondIs64), 12664, 12678, + /*12664*/ uint16(xCondDataSize), 12668, 12673, 0, + /*12668*/ uint16(xSetOp), uint16(JMP), + /*12670*/ uint16(xReadCw), + /*12671*/ uint16(xArgRel16), + /*12672*/ uint16(xMatch), + /*12673*/ uint16(xSetOp), uint16(JMP), + /*12675*/ uint16(xReadCd), + /*12676*/ uint16(xArgRel32), + /*12677*/ uint16(xMatch), + /*12678*/ uint16(xCondDataSize), 12682, 12673, 12687, + /*12682*/ uint16(xSetOp), uint16(JMP), + /*12684*/ uint16(xReadCd), + /*12685*/ uint16(xArgRel32), + /*12686*/ uint16(xMatch), + /*12687*/ uint16(xSetOp), uint16(JMP), + /*12689*/ uint16(xReadCd), + /*12690*/ uint16(xArgRel32), + /*12691*/ uint16(xMatch), + /*12692*/ uint16(xCondIs64), 12695, 0, + /*12695*/ uint16(xCondDataSize), 12699, 12704, 0, + /*12699*/ uint16(xSetOp), uint16(LJMP), + /*12701*/ uint16(xReadCd), + /*12702*/ uint16(xArgPtr16colon16), + /*12703*/ uint16(xMatch), + /*12704*/ uint16(xSetOp), uint16(LJMP), + /*12706*/ uint16(xReadCp), + /*12707*/ uint16(xArgPtr16colon32), + /*12708*/ uint16(xMatch), + /*12709*/ uint16(xSetOp), uint16(JMP), + /*12711*/ uint16(xReadCb), + /*12712*/ uint16(xArgRel8), + /*12713*/ uint16(xMatch), + /*12714*/ uint16(xSetOp), uint16(IN), + /*12716*/ uint16(xArgAL), + /*12717*/ uint16(xArgDX), + /*12718*/ uint16(xMatch), + /*12719*/ uint16(xCondDataSize), 12723, 12728, 12733, + /*12723*/ uint16(xSetOp), uint16(IN), + /*12725*/ uint16(xArgAX), + /*12726*/ uint16(xArgDX), + /*12727*/ uint16(xMatch), + /*12728*/ uint16(xSetOp), uint16(IN), + /*12730*/ uint16(xArgEAX), + /*12731*/ uint16(xArgDX), + /*12732*/ uint16(xMatch), + /*12733*/ uint16(xSetOp), uint16(IN), + /*12735*/ uint16(xArgEAX), + /*12736*/ uint16(xArgDX), + /*12737*/ uint16(xMatch), + /*12738*/ uint16(xSetOp), uint16(OUT), + /*12740*/ uint16(xArgDX), + /*12741*/ uint16(xArgAL), + /*12742*/ uint16(xMatch), + /*12743*/ uint16(xCondDataSize), 12747, 12752, 12757, + /*12747*/ uint16(xSetOp), uint16(OUT), + /*12749*/ uint16(xArgDX), + /*12750*/ uint16(xArgAX), + /*12751*/ uint16(xMatch), + /*12752*/ uint16(xSetOp), uint16(OUT), + /*12754*/ uint16(xArgDX), + /*12755*/ uint16(xArgEAX), + /*12756*/ uint16(xMatch), + /*12757*/ uint16(xSetOp), uint16(OUT), + /*12759*/ uint16(xArgDX), + /*12760*/ uint16(xArgEAX), + /*12761*/ uint16(xMatch), + /*12762*/ uint16(xSetOp), uint16(ICEBP), + /*12764*/ uint16(xMatch), + /*12765*/ uint16(xSetOp), uint16(HLT), + /*12767*/ uint16(xMatch), + /*12768*/ uint16(xSetOp), uint16(CMC), + /*12770*/ uint16(xMatch), + /*12771*/ uint16(xCondSlashR), + 12780, // 0 + 0, // 1 + 12786, // 2 + 12790, // 3 + 12794, // 4 + 12798, // 5 + 12802, // 6 + 12806, // 7 + /*12780*/ uint16(xSetOp), uint16(TEST), + /*12782*/ uint16(xReadIb), + /*12783*/ uint16(xArgRM8), + /*12784*/ uint16(xArgImm8u), + /*12785*/ uint16(xMatch), + /*12786*/ uint16(xSetOp), uint16(NOT), + /*12788*/ uint16(xArgRM8), + /*12789*/ uint16(xMatch), + /*12790*/ uint16(xSetOp), uint16(NEG), + /*12792*/ uint16(xArgRM8), + /*12793*/ uint16(xMatch), + /*12794*/ uint16(xSetOp), uint16(MUL), + /*12796*/ uint16(xArgRM8), + /*12797*/ uint16(xMatch), + /*12798*/ uint16(xSetOp), uint16(IMUL), + /*12800*/ uint16(xArgRM8), + /*12801*/ uint16(xMatch), + /*12802*/ uint16(xSetOp), uint16(DIV), + /*12804*/ uint16(xArgRM8), + /*12805*/ uint16(xMatch), + /*12806*/ uint16(xSetOp), uint16(IDIV), + /*12808*/ uint16(xArgRM8), + /*12809*/ uint16(xMatch), + /*12810*/ uint16(xCondSlashR), + 12819, // 0 + 0, // 1 + 12848, // 2 + 12871, // 3 + 12894, // 4 + 12917, // 5 + 12940, // 6 + 12963, // 7 + /*12819*/ uint16(xCondIs64), 12822, 12838, + /*12822*/ uint16(xCondDataSize), 12826, 12832, 0, + /*12826*/ uint16(xSetOp), uint16(TEST), + /*12828*/ uint16(xReadIw), + /*12829*/ uint16(xArgRM16), + /*12830*/ uint16(xArgImm16), + /*12831*/ uint16(xMatch), + /*12832*/ uint16(xSetOp), uint16(TEST), + /*12834*/ uint16(xReadId), + /*12835*/ uint16(xArgRM32), + /*12836*/ uint16(xArgImm32), + /*12837*/ uint16(xMatch), + /*12838*/ uint16(xCondDataSize), 12826, 12832, 12842, + /*12842*/ uint16(xSetOp), uint16(TEST), + /*12844*/ uint16(xReadId), + /*12845*/ uint16(xArgRM64), + /*12846*/ uint16(xArgImm32), + /*12847*/ uint16(xMatch), + /*12848*/ uint16(xCondIs64), 12851, 12863, + /*12851*/ uint16(xCondDataSize), 12855, 12859, 0, + /*12855*/ uint16(xSetOp), uint16(NOT), + /*12857*/ uint16(xArgRM16), + /*12858*/ uint16(xMatch), + /*12859*/ uint16(xSetOp), uint16(NOT), + /*12861*/ uint16(xArgRM32), + /*12862*/ uint16(xMatch), + /*12863*/ uint16(xCondDataSize), 12855, 12859, 12867, + /*12867*/ uint16(xSetOp), uint16(NOT), + /*12869*/ uint16(xArgRM64), + /*12870*/ uint16(xMatch), + /*12871*/ uint16(xCondIs64), 12874, 12886, + /*12874*/ uint16(xCondDataSize), 12878, 12882, 0, + /*12878*/ uint16(xSetOp), uint16(NEG), + /*12880*/ uint16(xArgRM16), + /*12881*/ uint16(xMatch), + /*12882*/ uint16(xSetOp), uint16(NEG), + /*12884*/ uint16(xArgRM32), + /*12885*/ uint16(xMatch), + /*12886*/ uint16(xCondDataSize), 12878, 12882, 12890, + /*12890*/ uint16(xSetOp), uint16(NEG), + /*12892*/ uint16(xArgRM64), + /*12893*/ uint16(xMatch), + /*12894*/ uint16(xCondIs64), 12897, 12909, + /*12897*/ uint16(xCondDataSize), 12901, 12905, 0, + /*12901*/ uint16(xSetOp), uint16(MUL), + /*12903*/ uint16(xArgRM16), + /*12904*/ uint16(xMatch), + /*12905*/ uint16(xSetOp), uint16(MUL), + /*12907*/ uint16(xArgRM32), + /*12908*/ uint16(xMatch), + /*12909*/ uint16(xCondDataSize), 12901, 12905, 12913, + /*12913*/ uint16(xSetOp), uint16(MUL), + /*12915*/ uint16(xArgRM64), + /*12916*/ uint16(xMatch), + /*12917*/ uint16(xCondIs64), 12920, 12932, + /*12920*/ uint16(xCondDataSize), 12924, 12928, 0, + /*12924*/ uint16(xSetOp), uint16(IMUL), + /*12926*/ uint16(xArgRM16), + /*12927*/ uint16(xMatch), + /*12928*/ uint16(xSetOp), uint16(IMUL), + /*12930*/ uint16(xArgRM32), + /*12931*/ uint16(xMatch), + /*12932*/ uint16(xCondDataSize), 12924, 12928, 12936, + /*12936*/ uint16(xSetOp), uint16(IMUL), + /*12938*/ uint16(xArgRM64), + /*12939*/ uint16(xMatch), + /*12940*/ uint16(xCondIs64), 12943, 12955, + /*12943*/ uint16(xCondDataSize), 12947, 12951, 0, + /*12947*/ uint16(xSetOp), uint16(DIV), + /*12949*/ uint16(xArgRM16), + /*12950*/ uint16(xMatch), + /*12951*/ uint16(xSetOp), uint16(DIV), + /*12953*/ uint16(xArgRM32), + /*12954*/ uint16(xMatch), + /*12955*/ uint16(xCondDataSize), 12947, 12951, 12959, + /*12959*/ uint16(xSetOp), uint16(DIV), + /*12961*/ uint16(xArgRM64), + /*12962*/ uint16(xMatch), + /*12963*/ uint16(xCondIs64), 12966, 12978, + /*12966*/ uint16(xCondDataSize), 12970, 12974, 0, + /*12970*/ uint16(xSetOp), uint16(IDIV), + /*12972*/ uint16(xArgRM16), + /*12973*/ uint16(xMatch), + /*12974*/ uint16(xSetOp), uint16(IDIV), + /*12976*/ uint16(xArgRM32), + /*12977*/ uint16(xMatch), + /*12978*/ uint16(xCondDataSize), 12970, 12974, 12982, + /*12982*/ uint16(xSetOp), uint16(IDIV), + /*12984*/ uint16(xArgRM64), + /*12985*/ uint16(xMatch), + /*12986*/ uint16(xSetOp), uint16(CLC), + /*12988*/ uint16(xMatch), + /*12989*/ uint16(xSetOp), uint16(STC), + /*12991*/ uint16(xMatch), + /*12992*/ uint16(xSetOp), uint16(CLI), + /*12994*/ uint16(xMatch), + /*12995*/ uint16(xSetOp), uint16(STI), + /*12997*/ uint16(xMatch), + /*12998*/ uint16(xSetOp), uint16(CLD), + /*13000*/ uint16(xMatch), + /*13001*/ uint16(xSetOp), uint16(STD), + /*13003*/ uint16(xMatch), + /*13004*/ uint16(xCondSlashR), + 13013, // 0 + 13017, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + /*13013*/ uint16(xSetOp), uint16(INC), + /*13015*/ uint16(xArgRM8), + /*13016*/ uint16(xMatch), + /*13017*/ uint16(xSetOp), uint16(DEC), + /*13019*/ uint16(xArgRM8), + /*13020*/ uint16(xMatch), + /*13021*/ uint16(xCondSlashR), + 13030, // 0 + 13053, // 1 + 13076, // 2 + 13095, // 3 + 13118, // 4 + 13137, // 5 + 13160, // 6 + 0, // 7 + /*13030*/ uint16(xCondIs64), 13033, 13045, + /*13033*/ uint16(xCondDataSize), 13037, 13041, 0, + /*13037*/ uint16(xSetOp), uint16(INC), + /*13039*/ uint16(xArgRM16), + /*13040*/ uint16(xMatch), + /*13041*/ uint16(xSetOp), uint16(INC), + /*13043*/ uint16(xArgRM32), + /*13044*/ uint16(xMatch), + /*13045*/ uint16(xCondDataSize), 13037, 13041, 13049, + /*13049*/ uint16(xSetOp), uint16(INC), + /*13051*/ uint16(xArgRM64), + /*13052*/ uint16(xMatch), + /*13053*/ uint16(xCondIs64), 13056, 13068, + /*13056*/ uint16(xCondDataSize), 13060, 13064, 0, + /*13060*/ uint16(xSetOp), uint16(DEC), + /*13062*/ uint16(xArgRM16), + /*13063*/ uint16(xMatch), + /*13064*/ uint16(xSetOp), uint16(DEC), + /*13066*/ uint16(xArgRM32), + /*13067*/ uint16(xMatch), + /*13068*/ uint16(xCondDataSize), 13060, 13064, 13072, + /*13072*/ uint16(xSetOp), uint16(DEC), + /*13074*/ uint16(xArgRM64), + /*13075*/ uint16(xMatch), + /*13076*/ uint16(xCondIs64), 13079, 13091, + /*13079*/ uint16(xCondDataSize), 13083, 13087, 0, + /*13083*/ uint16(xSetOp), uint16(CALL), + /*13085*/ uint16(xArgRM16), + /*13086*/ uint16(xMatch), + /*13087*/ uint16(xSetOp), uint16(CALL), + /*13089*/ uint16(xArgRM32), + /*13090*/ uint16(xMatch), + /*13091*/ uint16(xSetOp), uint16(CALL), + /*13093*/ uint16(xArgRM64), + /*13094*/ uint16(xMatch), + /*13095*/ uint16(xCondIs64), 13098, 13110, + /*13098*/ uint16(xCondDataSize), 13102, 13106, 0, + /*13102*/ uint16(xSetOp), uint16(LCALL), + /*13104*/ uint16(xArgM16colon16), + /*13105*/ uint16(xMatch), + /*13106*/ uint16(xSetOp), uint16(LCALL), + /*13108*/ uint16(xArgM16colon32), + /*13109*/ uint16(xMatch), + /*13110*/ uint16(xCondDataSize), 13102, 13106, 13114, + /*13114*/ uint16(xSetOp), uint16(LCALL), + /*13116*/ uint16(xArgM16colon64), + /*13117*/ uint16(xMatch), + /*13118*/ uint16(xCondIs64), 13121, 13133, + /*13121*/ uint16(xCondDataSize), 13125, 13129, 0, + /*13125*/ uint16(xSetOp), uint16(JMP), + /*13127*/ uint16(xArgRM16), + /*13128*/ uint16(xMatch), + /*13129*/ uint16(xSetOp), uint16(JMP), + /*13131*/ uint16(xArgRM32), + /*13132*/ uint16(xMatch), + /*13133*/ uint16(xSetOp), uint16(JMP), + /*13135*/ uint16(xArgRM64), + /*13136*/ uint16(xMatch), + /*13137*/ uint16(xCondIs64), 13140, 13152, + /*13140*/ uint16(xCondDataSize), 13144, 13148, 0, + /*13144*/ uint16(xSetOp), uint16(LJMP), + /*13146*/ uint16(xArgM16colon16), + /*13147*/ uint16(xMatch), + /*13148*/ uint16(xSetOp), uint16(LJMP), + /*13150*/ uint16(xArgM16colon32), + /*13151*/ uint16(xMatch), + /*13152*/ uint16(xCondDataSize), 13144, 13148, 13156, + /*13156*/ uint16(xSetOp), uint16(LJMP), + /*13158*/ uint16(xArgM16colon64), + /*13159*/ uint16(xMatch), + /*13160*/ uint16(xCondIs64), 13163, 13175, + /*13163*/ uint16(xCondDataSize), 13167, 13171, 0, + /*13167*/ uint16(xSetOp), uint16(PUSH), + /*13169*/ uint16(xArgRM16), + /*13170*/ uint16(xMatch), + /*13171*/ uint16(xSetOp), uint16(PUSH), + /*13173*/ uint16(xArgRM32), + /*13174*/ uint16(xMatch), + /*13175*/ uint16(xCondDataSize), 13167, 13179, 13183, + /*13179*/ uint16(xSetOp), uint16(PUSH), + /*13181*/ uint16(xArgRM64), + /*13182*/ uint16(xMatch), + /*13183*/ uint16(xSetOp), uint16(PUSH), + /*13185*/ uint16(xArgRM64), + /*13186*/ uint16(xMatch), +} + +const ( + _ Op = iota + + AAA + AAD + AAM + AAS + ADC + ADD + ADDPD + ADDPS + ADDSD + ADDSS + ADDSUBPD + ADDSUBPS + AESDEC + AESDECLAST + AESENC + AESENCLAST + AESIMC + AESKEYGENASSIST + AND + ANDNPD + ANDNPS + ANDPD + ANDPS + ARPL + BLENDPD + BLENDPS + BLENDVPD + BLENDVPS + BOUND + BSF + BSR + BSWAP + BT + BTC + BTR + BTS + CALL + CBW + CDQ + CDQE + CLC + CLD + CLFLUSH + CLI + CLTS + CMC + CMOVA + CMOVAE + CMOVB + CMOVBE + CMOVE + CMOVG + CMOVGE + CMOVL + CMOVLE + CMOVNE + CMOVNO + CMOVNP + CMOVNS + CMOVO + CMOVP + CMOVS + CMP + CMPPD + CMPPS + CMPSB + CMPSD + CMPSD_XMM + CMPSQ + CMPSS + CMPSW + CMPXCHG + CMPXCHG16B + CMPXCHG8B + COMISD + COMISS + CPUID + CQO + CRC32 + CVTDQ2PD + CVTDQ2PS + CVTPD2DQ + CVTPD2PI + CVTPD2PS + CVTPI2PD + CVTPI2PS + CVTPS2DQ + CVTPS2PD + CVTPS2PI + CVTSD2SI + CVTSD2SS + CVTSI2SD + CVTSI2SS + CVTSS2SD + CVTSS2SI + CVTTPD2DQ + CVTTPD2PI + CVTTPS2DQ + CVTTPS2PI + CVTTSD2SI + CVTTSS2SI + CWD + CWDE + DAA + DAS + DEC + DIV + DIVPD + DIVPS + DIVSD + DIVSS + DPPD + DPPS + EMMS + ENTER + EXTRACTPS + F2XM1 + FABS + FADD + FADDP + FBLD + FBSTP + FCHS + FCMOVB + FCMOVBE + FCMOVE + FCMOVNB + FCMOVNBE + FCMOVNE + FCMOVNU + FCMOVU + FCOM + FCOMI + FCOMIP + FCOMP + FCOMPP + FCOS + FDECSTP + FDIV + FDIVP + FDIVR + FDIVRP + FFREE + FFREEP + FIADD + FICOM + FICOMP + FIDIV + FIDIVR + FILD + FIMUL + FINCSTP + FIST + FISTP + FISTTP + FISUB + FISUBR + FLD + FLD1 + FLDCW + FLDENV + FLDL2E + FLDL2T + FLDLG2 + FLDPI + FMUL + FMULP + FNCLEX + FNINIT + FNOP + FNSAVE + FNSTCW + FNSTENV + FNSTSW + FPATAN + FPREM + FPREM1 + FPTAN + FRNDINT + FRSTOR + FSCALE + FSIN + FSINCOS + FSQRT + FST + FSTP + FSUB + FSUBP + FSUBR + FSUBRP + FTST + FUCOM + FUCOMI + FUCOMIP + FUCOMP + FUCOMPP + FWAIT + FXAM + FXCH + FXRSTOR + FXRSTOR64 + FXSAVE + FXSAVE64 + FXTRACT + FYL2X + FYL2XP1 + HADDPD + HADDPS + HLT + HSUBPD + HSUBPS + ICEBP + IDIV + IMUL + IN + INC + INSB + INSD + INSERTPS + INSW + INT + INTO + INVD + INVLPG + INVPCID + IRET + IRETD + IRETQ + JA + JAE + JB + JBE + JCXZ + JE + JECXZ + JG + JGE + JL + JLE + JMP + JNE + JNO + JNP + JNS + JO + JP + JRCXZ + JS + LAHF + LAR + LCALL + LDDQU + LDMXCSR + LDS + LEA + LEAVE + LES + LFENCE + LFS + LGDT + LGS + LIDT + LJMP + LLDT + LMSW + LODSB + LODSD + LODSQ + LODSW + LOOP + LOOPE + LOOPNE + LRET + LSL + LSS + LTR + LZCNT + MASKMOVDQU + MASKMOVQ + MAXPD + MAXPS + MAXSD + MAXSS + MFENCE + MINPD + MINPS + MINSD + MINSS + MONITOR + MOV + MOVAPD + MOVAPS + MOVBE + MOVD + MOVDDUP + MOVDQ2Q + MOVDQA + MOVDQU + MOVHLPS + MOVHPD + MOVHPS + MOVLHPS + MOVLPD + MOVLPS + MOVMSKPD + MOVMSKPS + MOVNTDQ + MOVNTDQA + MOVNTI + MOVNTPD + MOVNTPS + MOVNTQ + MOVNTSD + MOVNTSS + MOVQ + MOVQ2DQ + MOVSB + MOVSD + MOVSD_XMM + MOVSHDUP + MOVSLDUP + MOVSQ + MOVSS + MOVSW + MOVSX + MOVSXD + MOVUPD + MOVUPS + MOVZX + MPSADBW + MUL + MULPD + MULPS + MULSD + MULSS + MWAIT + NEG + NOP + NOT + OR + ORPD + ORPS + OUT + OUTSB + OUTSD + OUTSW + PABSB + PABSD + PABSW + PACKSSDW + PACKSSWB + PACKUSDW + PACKUSWB + PADDB + PADDD + PADDQ + PADDSB + PADDSW + PADDUSB + PADDUSW + PADDW + PALIGNR + PAND + PANDN + PAUSE + PAVGB + PAVGW + PBLENDVB + PBLENDW + PCLMULQDQ + PCMPEQB + PCMPEQD + PCMPEQQ + PCMPEQW + PCMPESTRI + PCMPESTRM + PCMPGTB + PCMPGTD + PCMPGTQ + PCMPGTW + PCMPISTRI + PCMPISTRM + PEXTRB + PEXTRD + PEXTRQ + PEXTRW + PHADDD + PHADDSW + PHADDW + PHMINPOSUW + PHSUBD + PHSUBSW + PHSUBW + PINSRB + PINSRD + PINSRQ + PINSRW + PMADDUBSW + PMADDWD + PMAXSB + PMAXSD + PMAXSW + PMAXUB + PMAXUD + PMAXUW + PMINSB + PMINSD + PMINSW + PMINUB + PMINUD + PMINUW + PMOVMSKB + PMOVSXBD + PMOVSXBQ + PMOVSXBW + PMOVSXDQ + PMOVSXWD + PMOVSXWQ + PMOVZXBD + PMOVZXBQ + PMOVZXBW + PMOVZXDQ + PMOVZXWD + PMOVZXWQ + PMULDQ + PMULHRSW + PMULHUW + PMULHW + PMULLD + PMULLW + PMULUDQ + POP + POPA + POPAD + POPCNT + POPF + POPFD + POPFQ + POR + PREFETCHNTA + PREFETCHT0 + PREFETCHT1 + PREFETCHT2 + PREFETCHW + PSADBW + PSHUFB + PSHUFD + PSHUFHW + PSHUFLW + PSHUFW + PSIGNB + PSIGND + PSIGNW + PSLLD + PSLLDQ + PSLLQ + PSLLW + PSRAD + PSRAW + PSRLD + PSRLDQ + PSRLQ + PSRLW + PSUBB + PSUBD + PSUBQ + PSUBSB + PSUBSW + PSUBUSB + PSUBUSW + PSUBW + PTEST + PUNPCKHBW + PUNPCKHDQ + PUNPCKHQDQ + PUNPCKHWD + PUNPCKLBW + PUNPCKLDQ + PUNPCKLQDQ + PUNPCKLWD + PUSH + PUSHA + PUSHAD + PUSHF + PUSHFD + PUSHFQ + PXOR + RCL + RCPPS + RCPSS + RCR + RDFSBASE + RDGSBASE + RDMSR + RDPMC + RDRAND + RDTSC + RDTSCP + RET + ROL + ROR + ROUNDPD + ROUNDPS + ROUNDSD + ROUNDSS + RSM + RSQRTPS + RSQRTSS + SAHF + SAR + SBB + SCASB + SCASD + SCASQ + SCASW + SETA + SETAE + SETB + SETBE + SETE + SETG + SETGE + SETL + SETLE + SETNE + SETNO + SETNP + SETNS + SETO + SETP + SETS + SFENCE + SGDT + SHL + SHLD + SHR + SHRD + SHUFPD + SHUFPS + SIDT + SLDT + SMSW + SQRTPD + SQRTPS + SQRTSD + SQRTSS + STC + STD + STI + STMXCSR + STOSB + STOSD + STOSQ + STOSW + STR + SUB + SUBPD + SUBPS + SUBSD + SUBSS + SWAPGS + SYSCALL + SYSENTER + SYSEXIT + SYSRET + TEST + TZCNT + UCOMISD + UCOMISS + UD1 + UD2 + UNPCKHPD + UNPCKHPS + UNPCKLPD + UNPCKLPS + VERR + VERW + WBINVD + WRFSBASE + WRGSBASE + WRMSR + XABORT + XADD + XBEGIN + XCHG + XEND + XGETBV + XLATB + XOR + XORPD + XORPS + XRSTOR + XRSTOR64 + XRSTORS + XRSTORS64 + XSAVE + XSAVE64 + XSAVEC + XSAVEC64 + XSAVEOPT + XSAVEOPT64 + XSAVES + XSAVES64 + XSETBV + XTEST +) + +const maxOp = XTEST + +var opNames = [...]string{ + AAA: "AAA", + AAD: "AAD", + AAM: "AAM", + AAS: "AAS", + ADC: "ADC", + ADD: "ADD", + ADDPD: "ADDPD", + ADDPS: "ADDPS", + ADDSD: "ADDSD", + ADDSS: "ADDSS", + ADDSUBPD: "ADDSUBPD", + ADDSUBPS: "ADDSUBPS", + AESDEC: "AESDEC", + AESDECLAST: "AESDECLAST", + AESENC: "AESENC", + AESENCLAST: "AESENCLAST", + AESIMC: "AESIMC", + AESKEYGENASSIST: "AESKEYGENASSIST", + AND: "AND", + ANDNPD: "ANDNPD", + ANDNPS: "ANDNPS", + ANDPD: "ANDPD", + ANDPS: "ANDPS", + ARPL: "ARPL", + BLENDPD: "BLENDPD", + BLENDPS: "BLENDPS", + BLENDVPD: "BLENDVPD", + BLENDVPS: "BLENDVPS", + BOUND: "BOUND", + BSF: "BSF", + BSR: "BSR", + BSWAP: "BSWAP", + BT: "BT", + BTC: "BTC", + BTR: "BTR", + BTS: "BTS", + CALL: "CALL", + CBW: "CBW", + CDQ: "CDQ", + CDQE: "CDQE", + CLC: "CLC", + CLD: "CLD", + CLFLUSH: "CLFLUSH", + CLI: "CLI", + CLTS: "CLTS", + CMC: "CMC", + CMOVA: "CMOVA", + CMOVAE: "CMOVAE", + CMOVB: "CMOVB", + CMOVBE: "CMOVBE", + CMOVE: "CMOVE", + CMOVG: "CMOVG", + CMOVGE: "CMOVGE", + CMOVL: "CMOVL", + CMOVLE: "CMOVLE", + CMOVNE: "CMOVNE", + CMOVNO: "CMOVNO", + CMOVNP: "CMOVNP", + CMOVNS: "CMOVNS", + CMOVO: "CMOVO", + CMOVP: "CMOVP", + CMOVS: "CMOVS", + CMP: "CMP", + CMPPD: "CMPPD", + CMPPS: "CMPPS", + CMPSB: "CMPSB", + CMPSD: "CMPSD", + CMPSD_XMM: "CMPSD_XMM", + CMPSQ: "CMPSQ", + CMPSS: "CMPSS", + CMPSW: "CMPSW", + CMPXCHG: "CMPXCHG", + CMPXCHG16B: "CMPXCHG16B", + CMPXCHG8B: "CMPXCHG8B", + COMISD: "COMISD", + COMISS: "COMISS", + CPUID: "CPUID", + CQO: "CQO", + CRC32: "CRC32", + CVTDQ2PD: "CVTDQ2PD", + CVTDQ2PS: "CVTDQ2PS", + CVTPD2DQ: "CVTPD2DQ", + CVTPD2PI: "CVTPD2PI", + CVTPD2PS: "CVTPD2PS", + CVTPI2PD: "CVTPI2PD", + CVTPI2PS: "CVTPI2PS", + CVTPS2DQ: "CVTPS2DQ", + CVTPS2PD: "CVTPS2PD", + CVTPS2PI: "CVTPS2PI", + CVTSD2SI: "CVTSD2SI", + CVTSD2SS: "CVTSD2SS", + CVTSI2SD: "CVTSI2SD", + CVTSI2SS: "CVTSI2SS", + CVTSS2SD: "CVTSS2SD", + CVTSS2SI: "CVTSS2SI", + CVTTPD2DQ: "CVTTPD2DQ", + CVTTPD2PI: "CVTTPD2PI", + CVTTPS2DQ: "CVTTPS2DQ", + CVTTPS2PI: "CVTTPS2PI", + CVTTSD2SI: "CVTTSD2SI", + CVTTSS2SI: "CVTTSS2SI", + CWD: "CWD", + CWDE: "CWDE", + DAA: "DAA", + DAS: "DAS", + DEC: "DEC", + DIV: "DIV", + DIVPD: "DIVPD", + DIVPS: "DIVPS", + DIVSD: "DIVSD", + DIVSS: "DIVSS", + DPPD: "DPPD", + DPPS: "DPPS", + EMMS: "EMMS", + ENTER: "ENTER", + EXTRACTPS: "EXTRACTPS", + F2XM1: "F2XM1", + FABS: "FABS", + FADD: "FADD", + FADDP: "FADDP", + FBLD: "FBLD", + FBSTP: "FBSTP", + FCHS: "FCHS", + FCMOVB: "FCMOVB", + FCMOVBE: "FCMOVBE", + FCMOVE: "FCMOVE", + FCMOVNB: "FCMOVNB", + FCMOVNBE: "FCMOVNBE", + FCMOVNE: "FCMOVNE", + FCMOVNU: "FCMOVNU", + FCMOVU: "FCMOVU", + FCOM: "FCOM", + FCOMI: "FCOMI", + FCOMIP: "FCOMIP", + FCOMP: "FCOMP", + FCOMPP: "FCOMPP", + FCOS: "FCOS", + FDECSTP: "FDECSTP", + FDIV: "FDIV", + FDIVP: "FDIVP", + FDIVR: "FDIVR", + FDIVRP: "FDIVRP", + FFREE: "FFREE", + FFREEP: "FFREEP", + FIADD: "FIADD", + FICOM: "FICOM", + FICOMP: "FICOMP", + FIDIV: "FIDIV", + FIDIVR: "FIDIVR", + FILD: "FILD", + FIMUL: "FIMUL", + FINCSTP: "FINCSTP", + FIST: "FIST", + FISTP: "FISTP", + FISTTP: "FISTTP", + FISUB: "FISUB", + FISUBR: "FISUBR", + FLD: "FLD", + FLD1: "FLD1", + FLDCW: "FLDCW", + FLDENV: "FLDENV", + FLDL2E: "FLDL2E", + FLDL2T: "FLDL2T", + FLDLG2: "FLDLG2", + FLDPI: "FLDPI", + FMUL: "FMUL", + FMULP: "FMULP", + FNCLEX: "FNCLEX", + FNINIT: "FNINIT", + FNOP: "FNOP", + FNSAVE: "FNSAVE", + FNSTCW: "FNSTCW", + FNSTENV: "FNSTENV", + FNSTSW: "FNSTSW", + FPATAN: "FPATAN", + FPREM: "FPREM", + FPREM1: "FPREM1", + FPTAN: "FPTAN", + FRNDINT: "FRNDINT", + FRSTOR: "FRSTOR", + FSCALE: "FSCALE", + FSIN: "FSIN", + FSINCOS: "FSINCOS", + FSQRT: "FSQRT", + FST: "FST", + FSTP: "FSTP", + FSUB: "FSUB", + FSUBP: "FSUBP", + FSUBR: "FSUBR", + FSUBRP: "FSUBRP", + FTST: "FTST", + FUCOM: "FUCOM", + FUCOMI: "FUCOMI", + FUCOMIP: "FUCOMIP", + FUCOMP: "FUCOMP", + FUCOMPP: "FUCOMPP", + FWAIT: "FWAIT", + FXAM: "FXAM", + FXCH: "FXCH", + FXRSTOR: "FXRSTOR", + FXRSTOR64: "FXRSTOR64", + FXSAVE: "FXSAVE", + FXSAVE64: "FXSAVE64", + FXTRACT: "FXTRACT", + FYL2X: "FYL2X", + FYL2XP1: "FYL2XP1", + HADDPD: "HADDPD", + HADDPS: "HADDPS", + HLT: "HLT", + HSUBPD: "HSUBPD", + HSUBPS: "HSUBPS", + ICEBP: "ICEBP", + IDIV: "IDIV", + IMUL: "IMUL", + IN: "IN", + INC: "INC", + INSB: "INSB", + INSD: "INSD", + INSERTPS: "INSERTPS", + INSW: "INSW", + INT: "INT", + INTO: "INTO", + INVD: "INVD", + INVLPG: "INVLPG", + INVPCID: "INVPCID", + IRET: "IRET", + IRETD: "IRETD", + IRETQ: "IRETQ", + JA: "JA", + JAE: "JAE", + JB: "JB", + JBE: "JBE", + JCXZ: "JCXZ", + JE: "JE", + JECXZ: "JECXZ", + JG: "JG", + JGE: "JGE", + JL: "JL", + JLE: "JLE", + JMP: "JMP", + JNE: "JNE", + JNO: "JNO", + JNP: "JNP", + JNS: "JNS", + JO: "JO", + JP: "JP", + JRCXZ: "JRCXZ", + JS: "JS", + LAHF: "LAHF", + LAR: "LAR", + LCALL: "LCALL", + LDDQU: "LDDQU", + LDMXCSR: "LDMXCSR", + LDS: "LDS", + LEA: "LEA", + LEAVE: "LEAVE", + LES: "LES", + LFENCE: "LFENCE", + LFS: "LFS", + LGDT: "LGDT", + LGS: "LGS", + LIDT: "LIDT", + LJMP: "LJMP", + LLDT: "LLDT", + LMSW: "LMSW", + LODSB: "LODSB", + LODSD: "LODSD", + LODSQ: "LODSQ", + LODSW: "LODSW", + LOOP: "LOOP", + LOOPE: "LOOPE", + LOOPNE: "LOOPNE", + LRET: "LRET", + LSL: "LSL", + LSS: "LSS", + LTR: "LTR", + LZCNT: "LZCNT", + MASKMOVDQU: "MASKMOVDQU", + MASKMOVQ: "MASKMOVQ", + MAXPD: "MAXPD", + MAXPS: "MAXPS", + MAXSD: "MAXSD", + MAXSS: "MAXSS", + MFENCE: "MFENCE", + MINPD: "MINPD", + MINPS: "MINPS", + MINSD: "MINSD", + MINSS: "MINSS", + MONITOR: "MONITOR", + MOV: "MOV", + MOVAPD: "MOVAPD", + MOVAPS: "MOVAPS", + MOVBE: "MOVBE", + MOVD: "MOVD", + MOVDDUP: "MOVDDUP", + MOVDQ2Q: "MOVDQ2Q", + MOVDQA: "MOVDQA", + MOVDQU: "MOVDQU", + MOVHLPS: "MOVHLPS", + MOVHPD: "MOVHPD", + MOVHPS: "MOVHPS", + MOVLHPS: "MOVLHPS", + MOVLPD: "MOVLPD", + MOVLPS: "MOVLPS", + MOVMSKPD: "MOVMSKPD", + MOVMSKPS: "MOVMSKPS", + MOVNTDQ: "MOVNTDQ", + MOVNTDQA: "MOVNTDQA", + MOVNTI: "MOVNTI", + MOVNTPD: "MOVNTPD", + MOVNTPS: "MOVNTPS", + MOVNTQ: "MOVNTQ", + MOVNTSD: "MOVNTSD", + MOVNTSS: "MOVNTSS", + MOVQ: "MOVQ", + MOVQ2DQ: "MOVQ2DQ", + MOVSB: "MOVSB", + MOVSD: "MOVSD", + MOVSD_XMM: "MOVSD_XMM", + MOVSHDUP: "MOVSHDUP", + MOVSLDUP: "MOVSLDUP", + MOVSQ: "MOVSQ", + MOVSS: "MOVSS", + MOVSW: "MOVSW", + MOVSX: "MOVSX", + MOVSXD: "MOVSXD", + MOVUPD: "MOVUPD", + MOVUPS: "MOVUPS", + MOVZX: "MOVZX", + MPSADBW: "MPSADBW", + MUL: "MUL", + MULPD: "MULPD", + MULPS: "MULPS", + MULSD: "MULSD", + MULSS: "MULSS", + MWAIT: "MWAIT", + NEG: "NEG", + NOP: "NOP", + NOT: "NOT", + OR: "OR", + ORPD: "ORPD", + ORPS: "ORPS", + OUT: "OUT", + OUTSB: "OUTSB", + OUTSD: "OUTSD", + OUTSW: "OUTSW", + PABSB: "PABSB", + PABSD: "PABSD", + PABSW: "PABSW", + PACKSSDW: "PACKSSDW", + PACKSSWB: "PACKSSWB", + PACKUSDW: "PACKUSDW", + PACKUSWB: "PACKUSWB", + PADDB: "PADDB", + PADDD: "PADDD", + PADDQ: "PADDQ", + PADDSB: "PADDSB", + PADDSW: "PADDSW", + PADDUSB: "PADDUSB", + PADDUSW: "PADDUSW", + PADDW: "PADDW", + PALIGNR: "PALIGNR", + PAND: "PAND", + PANDN: "PANDN", + PAUSE: "PAUSE", + PAVGB: "PAVGB", + PAVGW: "PAVGW", + PBLENDVB: "PBLENDVB", + PBLENDW: "PBLENDW", + PCLMULQDQ: "PCLMULQDQ", + PCMPEQB: "PCMPEQB", + PCMPEQD: "PCMPEQD", + PCMPEQQ: "PCMPEQQ", + PCMPEQW: "PCMPEQW", + PCMPESTRI: "PCMPESTRI", + PCMPESTRM: "PCMPESTRM", + PCMPGTB: "PCMPGTB", + PCMPGTD: "PCMPGTD", + PCMPGTQ: "PCMPGTQ", + PCMPGTW: "PCMPGTW", + PCMPISTRI: "PCMPISTRI", + PCMPISTRM: "PCMPISTRM", + PEXTRB: "PEXTRB", + PEXTRD: "PEXTRD", + PEXTRQ: "PEXTRQ", + PEXTRW: "PEXTRW", + PHADDD: "PHADDD", + PHADDSW: "PHADDSW", + PHADDW: "PHADDW", + PHMINPOSUW: "PHMINPOSUW", + PHSUBD: "PHSUBD", + PHSUBSW: "PHSUBSW", + PHSUBW: "PHSUBW", + PINSRB: "PINSRB", + PINSRD: "PINSRD", + PINSRQ: "PINSRQ", + PINSRW: "PINSRW", + PMADDUBSW: "PMADDUBSW", + PMADDWD: "PMADDWD", + PMAXSB: "PMAXSB", + PMAXSD: "PMAXSD", + PMAXSW: "PMAXSW", + PMAXUB: "PMAXUB", + PMAXUD: "PMAXUD", + PMAXUW: "PMAXUW", + PMINSB: "PMINSB", + PMINSD: "PMINSD", + PMINSW: "PMINSW", + PMINUB: "PMINUB", + PMINUD: "PMINUD", + PMINUW: "PMINUW", + PMOVMSKB: "PMOVMSKB", + PMOVSXBD: "PMOVSXBD", + PMOVSXBQ: "PMOVSXBQ", + PMOVSXBW: "PMOVSXBW", + PMOVSXDQ: "PMOVSXDQ", + PMOVSXWD: "PMOVSXWD", + PMOVSXWQ: "PMOVSXWQ", + PMOVZXBD: "PMOVZXBD", + PMOVZXBQ: "PMOVZXBQ", + PMOVZXBW: "PMOVZXBW", + PMOVZXDQ: "PMOVZXDQ", + PMOVZXWD: "PMOVZXWD", + PMOVZXWQ: "PMOVZXWQ", + PMULDQ: "PMULDQ", + PMULHRSW: "PMULHRSW", + PMULHUW: "PMULHUW", + PMULHW: "PMULHW", + PMULLD: "PMULLD", + PMULLW: "PMULLW", + PMULUDQ: "PMULUDQ", + POP: "POP", + POPA: "POPA", + POPAD: "POPAD", + POPCNT: "POPCNT", + POPF: "POPF", + POPFD: "POPFD", + POPFQ: "POPFQ", + POR: "POR", + PREFETCHNTA: "PREFETCHNTA", + PREFETCHT0: "PREFETCHT0", + PREFETCHT1: "PREFETCHT1", + PREFETCHT2: "PREFETCHT2", + PREFETCHW: "PREFETCHW", + PSADBW: "PSADBW", + PSHUFB: "PSHUFB", + PSHUFD: "PSHUFD", + PSHUFHW: "PSHUFHW", + PSHUFLW: "PSHUFLW", + PSHUFW: "PSHUFW", + PSIGNB: "PSIGNB", + PSIGND: "PSIGND", + PSIGNW: "PSIGNW", + PSLLD: "PSLLD", + PSLLDQ: "PSLLDQ", + PSLLQ: "PSLLQ", + PSLLW: "PSLLW", + PSRAD: "PSRAD", + PSRAW: "PSRAW", + PSRLD: "PSRLD", + PSRLDQ: "PSRLDQ", + PSRLQ: "PSRLQ", + PSRLW: "PSRLW", + PSUBB: "PSUBB", + PSUBD: "PSUBD", + PSUBQ: "PSUBQ", + PSUBSB: "PSUBSB", + PSUBSW: "PSUBSW", + PSUBUSB: "PSUBUSB", + PSUBUSW: "PSUBUSW", + PSUBW: "PSUBW", + PTEST: "PTEST", + PUNPCKHBW: "PUNPCKHBW", + PUNPCKHDQ: "PUNPCKHDQ", + PUNPCKHQDQ: "PUNPCKHQDQ", + PUNPCKHWD: "PUNPCKHWD", + PUNPCKLBW: "PUNPCKLBW", + PUNPCKLDQ: "PUNPCKLDQ", + PUNPCKLQDQ: "PUNPCKLQDQ", + PUNPCKLWD: "PUNPCKLWD", + PUSH: "PUSH", + PUSHA: "PUSHA", + PUSHAD: "PUSHAD", + PUSHF: "PUSHF", + PUSHFD: "PUSHFD", + PUSHFQ: "PUSHFQ", + PXOR: "PXOR", + RCL: "RCL", + RCPPS: "RCPPS", + RCPSS: "RCPSS", + RCR: "RCR", + RDFSBASE: "RDFSBASE", + RDGSBASE: "RDGSBASE", + RDMSR: "RDMSR", + RDPMC: "RDPMC", + RDRAND: "RDRAND", + RDTSC: "RDTSC", + RDTSCP: "RDTSCP", + RET: "RET", + ROL: "ROL", + ROR: "ROR", + ROUNDPD: "ROUNDPD", + ROUNDPS: "ROUNDPS", + ROUNDSD: "ROUNDSD", + ROUNDSS: "ROUNDSS", + RSM: "RSM", + RSQRTPS: "RSQRTPS", + RSQRTSS: "RSQRTSS", + SAHF: "SAHF", + SAR: "SAR", + SBB: "SBB", + SCASB: "SCASB", + SCASD: "SCASD", + SCASQ: "SCASQ", + SCASW: "SCASW", + SETA: "SETA", + SETAE: "SETAE", + SETB: "SETB", + SETBE: "SETBE", + SETE: "SETE", + SETG: "SETG", + SETGE: "SETGE", + SETL: "SETL", + SETLE: "SETLE", + SETNE: "SETNE", + SETNO: "SETNO", + SETNP: "SETNP", + SETNS: "SETNS", + SETO: "SETO", + SETP: "SETP", + SETS: "SETS", + SFENCE: "SFENCE", + SGDT: "SGDT", + SHL: "SHL", + SHLD: "SHLD", + SHR: "SHR", + SHRD: "SHRD", + SHUFPD: "SHUFPD", + SHUFPS: "SHUFPS", + SIDT: "SIDT", + SLDT: "SLDT", + SMSW: "SMSW", + SQRTPD: "SQRTPD", + SQRTPS: "SQRTPS", + SQRTSD: "SQRTSD", + SQRTSS: "SQRTSS", + STC: "STC", + STD: "STD", + STI: "STI", + STMXCSR: "STMXCSR", + STOSB: "STOSB", + STOSD: "STOSD", + STOSQ: "STOSQ", + STOSW: "STOSW", + STR: "STR", + SUB: "SUB", + SUBPD: "SUBPD", + SUBPS: "SUBPS", + SUBSD: "SUBSD", + SUBSS: "SUBSS", + SWAPGS: "SWAPGS", + SYSCALL: "SYSCALL", + SYSENTER: "SYSENTER", + SYSEXIT: "SYSEXIT", + SYSRET: "SYSRET", + TEST: "TEST", + TZCNT: "TZCNT", + UCOMISD: "UCOMISD", + UCOMISS: "UCOMISS", + UD1: "UD1", + UD2: "UD2", + UNPCKHPD: "UNPCKHPD", + UNPCKHPS: "UNPCKHPS", + UNPCKLPD: "UNPCKLPD", + UNPCKLPS: "UNPCKLPS", + VERR: "VERR", + VERW: "VERW", + WBINVD: "WBINVD", + WRFSBASE: "WRFSBASE", + WRGSBASE: "WRGSBASE", + WRMSR: "WRMSR", + XABORT: "XABORT", + XADD: "XADD", + XBEGIN: "XBEGIN", + XCHG: "XCHG", + XEND: "XEND", + XGETBV: "XGETBV", + XLATB: "XLATB", + XOR: "XOR", + XORPD: "XORPD", + XORPS: "XORPS", + XRSTOR: "XRSTOR", + XRSTOR64: "XRSTOR64", + XRSTORS: "XRSTORS", + XRSTORS64: "XRSTORS64", + XSAVE: "XSAVE", + XSAVE64: "XSAVE64", + XSAVEC: "XSAVEC", + XSAVEC64: "XSAVEC64", + XSAVEOPT: "XSAVEOPT", + XSAVEOPT64: "XSAVEOPT64", + XSAVES: "XSAVES", + XSAVES64: "XSAVES64", + XSETBV: "XSETBV", + XTEST: "XTEST", +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 7153f2e..9f40335 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -5,14 +5,110 @@ { "checksumSHA1": "OeOvZ+3A1tRBdMD8GuS6R9zcnqA=", "path": "github.com/astaxie/beego/swagger", - "revision": "a20ccde90d75695e4f0ae0353c88dba9781d366c", - "revisionTime": "2016-12-05T14:58:29Z" + "revision": "323a1c4214101331a4b71922c23d19b7409ac71f", + "revisionTime": "2017-03-06T13:59:04Z" }, { - "checksumSHA1": "95wt85GTZG0zi3Zk8g2jOVFV6Zg=", + "checksumSHA1": "epd3Y7nD7QVzTW0ppwK+q4pKo/4=", "path": "github.com/astaxie/beego/utils", - "revision": "a20ccde90d75695e4f0ae0353c88dba9781d366c", - "revisionTime": "2016-12-05T14:58:29Z" + "revision": "323a1c4214101331a4b71922c23d19b7409ac71f", + "revisionTime": "2017-03-06T13:59:04Z" + }, + { + "checksumSHA1": "Ay6dg3VVgggBHMsytbc+U4Wutyc=", + "path": "github.com/derekparker/delve/pkg/config", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "i4N90QPS76SMH2GjkJKjuS+z4xI=", + "path": "github.com/derekparker/delve/pkg/dwarf/frame", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "3pNKXngpbU4tnDOZc1ez6ywk7GA=", + "path": "github.com/derekparker/delve/pkg/dwarf/line", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "mOPdy13ztM3W5WMt3vVUq00AXfg=", + "path": "github.com/derekparker/delve/pkg/dwarf/op", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "hqg+xjH/qCO0CQokj5L1qD5lBmE=", + "path": "github.com/derekparker/delve/pkg/dwarf/reader", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "QkHSoN99PlCYaEgChgPaEBmUWbk=", + "path": "github.com/derekparker/delve/pkg/dwarf/util", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "KH9MVb6MX5iPgRjySRZHQa324Sw=", + "path": "github.com/derekparker/delve/pkg/proc", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "9dbHlIWbcf3jXVu6zRjZvJnDq4c=", + "path": "github.com/derekparker/delve/pkg/target", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "nqWjcE4SeTBNSuYlh6MJ8akB0cM=", + "path": "github.com/derekparker/delve/pkg/terminal", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "xRa64kuzCXVktmGscs1vCz9jIHs=", + "path": "github.com/derekparker/delve/pkg/version", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "BPHre0My8iszpkoNcX4ljtrz1dA=", + "path": "github.com/derekparker/delve/service", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "xMPjvGhTumLbAUApyLI/7UnC7sQ=", + "path": "github.com/derekparker/delve/service/api", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "/EXcw7FytgML9fdbMV0pxDBJJE0=", + "path": "github.com/derekparker/delve/service/debugger", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "d73mTsiCuYYpDaVs9QtozhzMDU0=", + "path": "github.com/derekparker/delve/service/rpc1", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "B+J0KRNuX0anRlif3mWXhBQhnVo=", + "path": "github.com/derekparker/delve/service/rpc2", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "PsNfnfv8GS79AG225Q/h57q/6F4=", + "path": "github.com/derekparker/delve/service/rpccommon", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" }, { "checksumSHA1": "hveFTNQ9YEyYRs6SWuXM+XU9qRI=", @@ -27,22 +123,10 @@ "revisionTime": "2016-01-13T11:48:05Z" }, { - "checksumSHA1": "dyGQP5AipmInoTQmnqvbFmUORpk=", + "checksumSHA1": "G778A9feKkdW7ZjeDdj5qoU0Ku4=", "path": "github.com/gorilla/websocket", - "revision": "a68708917c6a4f06314ab4e52493cc61359c9d42", - "revisionTime": "2016-06-06T23:20:22Z" - }, - { - "checksumSHA1": "ZxzYc1JwJ3U6kZbw/KGuPko5lSY=", - "path": "github.com/howeyc/fsnotify", - "revision": "f0c08ee9c60704c1879025f2ae0ff3e000082c13", - "revisionTime": "2015-10-03T19:46:02Z" - }, - { - "checksumSHA1": "tewA7jXVGCw1zb5mA0BDecWi4iQ=", - "path": "github.com/jtolds/gls", - "revision": "8ddce2a84170772b95dd5d576c48d517b22cac63", - "revisionTime": "2016-01-05T22:08:40Z" + "revision": "b258b4fadb573ac412f187b9f31974ea99d32f50", + "revisionTime": "2017-03-02T22:46:13Z" }, { "checksumSHA1": "dNYxHiBLalTqluak2/Z8c3RsSEM=", @@ -57,34 +141,46 @@ "revisionTime": "2016-08-06T14:40:29Z" }, { - "checksumSHA1": "0DtXHkHCB8kOYM15F+Y5WYMMMuc=", - "path": "github.com/smartystreets/assertions", - "revision": "edb6e295a22c57a2aa353b2f0729b6eff9f9f4b7", - "revisionTime": "2015-12-10T17:08:24Z" + "checksumSHA1": "rCffFCN6TpDAN3Jylyo8RFzhQ9E=", + "origin": "github.com/derekparker/delve/vendor/github.com/mattn/go-colorable", + "path": "github.com/mattn/go-colorable", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" }, { - "checksumSHA1": "QCsUvPHx/Ifqm+sJmocjSvePAIc=", - "path": "github.com/smartystreets/assertions/internal/oglematchers", - "revision": "edb6e295a22c57a2aa353b2f0729b6eff9f9f4b7", - "revisionTime": "2015-12-10T17:08:24Z" + "checksumSHA1": "NkbetqlpWBi3gP08JDneC+axTKw=", + "origin": "github.com/derekparker/delve/vendor/github.com/mattn/go-isatty", + "path": "github.com/mattn/go-isatty", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" }, { - "checksumSHA1": "fQeXVv5U9dlo3ufH2vjk1GNf4Lo=", - "path": "github.com/smartystreets/goconvey/convey", - "revision": "a2d5d788f3afbce0989463251ccc5492fad832df", - "revisionTime": "2015-12-28T21:47:19Z" + "checksumSHA1": "i8KS96zyCztA4003YeqcAmpcXXs=", + "origin": "github.com/derekparker/delve/vendor/github.com/peterh/liner", + "path": "github.com/peterh/liner", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" }, { - "checksumSHA1": "9LakndErFi5uCXtY1KWl0iRnT4c=", - "path": "github.com/smartystreets/goconvey/convey/gotest", - "revision": "a2d5d788f3afbce0989463251ccc5492fad832df", - "revisionTime": "2015-12-28T21:47:19Z" + "checksumSHA1": "1TxpZhEa9Ez1pq+kffwve9VUMug=", + "origin": "github.com/derekparker/delve/vendor/golang.org/x/debug/dwarf", + "path": "golang.org/x/debug/dwarf", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" }, { - "checksumSHA1": "Ht2/XG8aSW7vWbwav9z5jKyTzzw=", - "path": "github.com/smartystreets/goconvey/convey/reporting", - "revision": "a2d5d788f3afbce0989463251ccc5492fad832df", - "revisionTime": "2015-12-28T21:47:19Z" + "checksumSHA1": "dVu8Q/oko6zBz5UkwkrDyPHR8fU=", + "origin": "github.com/derekparker/delve/vendor/golang.org/x/debug/elf", + "path": "golang.org/x/debug/elf", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, + { + "checksumSHA1": "OktQbhBwXQo+frEBu9j+mbSn2T8=", + "origin": "github.com/derekparker/delve/vendor/golang.org/x/debug/macho", + "path": "golang.org/x/debug/macho", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" }, { "checksumSHA1": "NIg5qnKx/D8Th7YX882++siXTDY=", @@ -92,11 +188,25 @@ "revision": "131454b5606f5f11f6926156504d8ec772484f1d", "revisionTime": "2015-09-10T19:29:23Z" }, + { + "checksumSHA1": "K/B/XoWtkUDe+j1yIR8JPbpPW7Y=", + "origin": "github.com/derekparker/delve/vendor/golang.org/x/sys/windows", + "path": "golang.org/x/sys/windows", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" + }, { "checksumSHA1": "+OgOXBoiQ+X+C2dsAeiOHwBIEH0=", "path": "gopkg.in/yaml.v2", "revision": "a83829b6f1293c91addabc89d0571c246397bbf4", "revisionTime": "2016-03-01T20:40:22Z" + }, + { + "checksumSHA1": "AfKaQYT0TjxxZewjMk36e3GsVV4=", + "origin": "github.com/derekparker/delve/vendor/rsc.io/x86/x86asm", + "path": "rsc.io/x86/x86asm", + "revision": "ab7367ed2bf15044f7bca97147a802f77b875797", + "revisionTime": "2017-03-13T17:59:34Z" } ], "rootPath": "github.com/beego/bee"