mirror of
				https://github.com/beego/bee.git
				synced 2025-10-31 17:33:26 +00:00 
			
		
		
		
	Fix conflicts & Merge branch 'develop'
This commit is contained in:
		
							
								
								
									
										16
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								.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/) | ||||
|   | ||||
							
								
								
									
										3
									
								
								Beefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Beefile
									
									
									
									
									
								
							| @@ -1,7 +1,4 @@ | ||||
| version: 0 | ||||
| gopm: | ||||
|   enable: false | ||||
|   install: false | ||||
| go_install: false | ||||
| watch_ext: [] | ||||
| dir_structure: | ||||
|   | ||||
							
								
								
									
										81
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								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: | ||||
|   | ||||
							
								
								
									
										280
									
								
								autorouter.go
									
									
									
									
									
								
							
							
						
						
									
										280
									
								
								autorouter.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestGetControllerInfo(t *testing.T) { | ||||
| 	getControllerInfo("testdata/router/") | ||||
| } | ||||
							
								
								
									
										258
									
								
								bee.go
									
									
									
									
									
								
							
							
						
						
									
										258
									
								
								bee.go
									
									
									
									
									
								
							| @@ -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 <this-command>' 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) | ||||
| } | ||||
							
								
								
									
										4
									
								
								bee.json
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								bee.json
									
									
									
									
									
								
							| @@ -1,9 +1,5 @@ | ||||
| { | ||||
| 	"version": 0, | ||||
| 	"gopm": { | ||||
| 		"enable": false, | ||||
| 		"install": false | ||||
| 	}, | ||||
| 	"go_install": false, | ||||
| 	"watch_ext": [], | ||||
| 	"dir_structure": { | ||||
|   | ||||
							
								
								
									
										101
									
								
								cmd/bee.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								cmd/bee.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
| @@ -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 | ||||
| } | ||||
| @@ -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 | ||||
| 		} | ||||
| @@ -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 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										94
									
								
								cmd/commands/command.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								cmd/commands/command.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <this-command>' 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 | ||||
| } | ||||
							
								
								
									
										135
									
								
								cmd/commands/dlv/dlv.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								cmd/commands/dlv/dlv.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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...) | ||||
| } | ||||
| @@ -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.") | ||||
| } | ||||
							
								
								
									
										216
									
								
								cmd/commands/generate/generate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								cmd/commands/generate/generate.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										119
									
								
								cmd/commands/hprose/hprose.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								cmd/commands/hprose/hprose.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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) | ||||
| } | ||||
| @@ -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 = `<!DOCTYPE html> | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
| @@ -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 | ||||
| } | ||||
							
								
								
									
										102
									
								
								cmd/commands/rs/rs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								cmd/commands/rs/rs.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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() | ||||
| } | ||||
							
								
								
									
										88
									
								
								cmd/commands/run/docs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								cmd/commands/run/docs.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
| @@ -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 | ||||
| 	} | ||||
| 
 | ||||
| @@ -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 | ||||
| 		} | ||||
| 	} | ||||
| @@ -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 | ||||
| @@ -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) | ||||
| } | ||||
| @@ -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] | ||||
| } | ||||
							
								
								
									
										261
									
								
								code.go
									
									
									
									
									
								
							
							
						
						
									
										261
									
								
								code.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										177
									
								
								conf.go
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								conf.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										159
									
								
								config/conf.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								config/conf.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										200
									
								
								g.go
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								g.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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)) | ||||
| } | ||||
							
								
								
									
										23
									
								
								generate/g.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								generate/g.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| @@ -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 <null> 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 <null> 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)), "/") | ||||
| @@ -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) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -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) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -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) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -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 | ||||
							
								
								
									
										50
									
								
								generate/g_scaffold.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								generate/g_scaffold.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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)) | ||||
| } | ||||
| @@ -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) | ||||
| 	} | ||||
| } | ||||
| @@ -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 | ||||
| 	} | ||||
| 
 | ||||
							
								
								
									
										369
									
								
								hproseapp.go
									
									
									
									
									
								
							
							
						
						
									
										369
									
								
								hproseapp.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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)) | ||||
| } | ||||
| @@ -14,7 +14,7 @@ | ||||
| 
 | ||||
| // +build !windows | ||||
| 
 | ||||
| package main | ||||
| package colors | ||||
| 
 | ||||
| import "io" | ||||
| 
 | ||||
| @@ -14,7 +14,7 @@ | ||||
| 
 | ||||
| // +build windows | ||||
| 
 | ||||
| package main | ||||
| package colors | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| @@ -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 | ||||
							
								
								
									
										77
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										155
									
								
								rundocs.go
									
									
									
									
									
								
							
							
						
						
									
										155
									
								
								rundocs.go
									
									
									
									
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										102
									
								
								test.go
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								test.go
									
									
									
									
									
								
							| @@ -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") | ||||
| } | ||||
							
								
								
									
										28
									
								
								testdata/router/router.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								testdata/router/router.go
									
									
									
									
										vendored
									
									
								
							| @@ -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() { | ||||
|  | ||||
| } | ||||
							
								
								
									
										14
									
								
								utils/doc_value.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								utils/doc_value.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										14
									
								
								utils/list_opts.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								utils/list_opts.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										84
									
								
								utils/notification.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								utils/notification.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										15
									
								
								utils/str_flag.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								utils/str_flag.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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 | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/github.com/astaxie/beego/utils/safemap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/astaxie/beego/utils/safemap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -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) | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/jtolds/gls/LICENSE → vendor/github.com/derekparker/delve/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/jtolds/gls/LICENSE → vendor/github.com/derekparker/delve/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -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 | ||||
							
								
								
									
										134
									
								
								vendor/github.com/derekparker/delve/pkg/config/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								vendor/github.com/derekparker/delve/pkg/config/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										95
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/entries.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/entries.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										164
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/expression_constants.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/expression_constants.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| ) | ||||
							
								
								
									
										125
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										429
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/table.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/frame/table.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										122
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/line/line_parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/line/line_parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										267
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/line/state_machine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/line/state_machine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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. | ||||
| } | ||||
							
								
								
									
										84
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/op/op.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/op/op.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										345
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/reader/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										345
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/reader/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										81
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/util/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/derekparker/delve/pkg/dwarf/util/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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)) | ||||
| } | ||||
							
								
								
									
										79
									
								
								vendor/github.com/derekparker/delve/pkg/proc/arch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/derekparker/delve/pkg/proc/arch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										163
									
								
								vendor/github.com/derekparker/delve/pkg/proc/breakpoints.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								vendor/github.com/derekparker/delve/pkg/proc/breakpoints.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										67
									
								
								vendor/github.com/derekparker/delve/pkg/proc/disasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/derekparker/delve/pkg/proc/disasm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										184
									
								
								vendor/github.com/derekparker/delve/pkg/proc/disasm_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								vendor/github.com/derekparker/delve/pkg/proc/disasm_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										9
									
								
								vendor/github.com/derekparker/delve/pkg/proc/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/derekparker/delve/pkg/proc/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
							
								
								
									
										1131
									
								
								vendor/github.com/derekparker/delve/pkg/proc/eval.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1131
									
								
								vendor/github.com/derekparker/delve/pkg/proc/eval.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										283
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exc.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exc.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,283 @@ | ||||
| #ifndef	_exc_user_ | ||||
| #define	_exc_user_ | ||||
|  | ||||
| /* Module exc */ | ||||
|  | ||||
| #include <string.h> | ||||
| #include <mach/ndr.h> | ||||
| #include <mach/boolean.h> | ||||
| #include <mach/kern_return.h> | ||||
| #include <mach/notify.h> | ||||
| #include <mach/mach_types.h> | ||||
| #include <mach/message.h> | ||||
| #include <mach/mig_errors.h> | ||||
| #include <mach/port.h> | ||||
| 	 | ||||
| /* BEGIN VOUCHER CODE */ | ||||
|  | ||||
| #ifndef KERNEL | ||||
| #if defined(__has_include) | ||||
| #if __has_include(<mach/mig_voucher_support.h>) | ||||
| #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(<mach/mach_voucher_types.h>) | ||||
| #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 <mach/std_types.h> | ||||
| #include <mach/mig.h> | ||||
| #include <mach/mig.h> | ||||
| #include <mach/mach_types.h> | ||||
|  | ||||
| #ifdef __BeforeMigUserHeader | ||||
| __BeforeMigUserHeader | ||||
| #endif /* __BeforeMigUserHeader */ | ||||
|  | ||||
| #include <sys/cdefs.h> | ||||
| __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_ */ | ||||
							
								
								
									
										768
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exc_user_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										768
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exc_user_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										112
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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); | ||||
| } | ||||
							
								
								
									
										10
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/derekparker/delve/pkg/proc/exec_darwin.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #include "proc_darwin.h" | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <sys/ptrace.h> | ||||
| #include <errno.h> | ||||
| #include <stdlib.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| int | ||||
| fork_exec(char *, char **, int, char *, task_t*, mach_port_t*, mach_port_t*, mach_port_t*); | ||||
							
								
								
									
										117
									
								
								vendor/github.com/derekparker/delve/pkg/proc/go_version.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/github.com/derekparker/delve/pkg/proc/go_version.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										119
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mach_exc.defs
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mach_exc.defs
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 <mach/std_types.defs> | ||||
| #include <mach/mach_types.defs> | ||||
|  | ||||
| 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 : */ | ||||
							
								
								
									
										283
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mach_exc.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mach_exc.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,283 @@ | ||||
| #ifndef	_mach_exc_user_ | ||||
| #define	_mach_exc_user_ | ||||
|  | ||||
| /* Module mach_exc */ | ||||
|  | ||||
| #include <string.h> | ||||
| #include <mach/ndr.h> | ||||
| #include <mach/boolean.h> | ||||
| #include <mach/kern_return.h> | ||||
| #include <mach/notify.h> | ||||
| #include <mach/mach_types.h> | ||||
| #include <mach/message.h> | ||||
| #include <mach/mig_errors.h> | ||||
| #include <mach/port.h> | ||||
|  | ||||
| /* BEGIN VOUCHER CODE */ | ||||
|  | ||||
| #ifndef KERNEL | ||||
| #if defined(__has_include) | ||||
| #if __has_include(<mach/mig_voucher_support.h>) | ||||
| #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(<mach/mach_voucher_types.h>) | ||||
| #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 <mach/std_types.h> | ||||
| #include <mach/mig.h> | ||||
| #include <mach/mig.h> | ||||
| #include <mach/mach_types.h> | ||||
|  | ||||
| #ifdef __BeforeMigUserHeader | ||||
| __BeforeMigUserHeader | ||||
| #endif /* __BeforeMigUserHeader */ | ||||
|  | ||||
| #include <sys/cdefs.h> | ||||
| __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_ */ | ||||
							
								
								
									
										768
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mach_exc_user_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										768
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mach_exc_user_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										57
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mem.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/derekparker/delve/pkg/proc/mem.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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} | ||||
| } | ||||
							
								
								
									
										189
									
								
								vendor/github.com/derekparker/delve/pkg/proc/moduledata.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								vendor/github.com/derekparker/delve/pkg/proc/moduledata.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										986
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										986
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										231
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,231 @@ | ||||
| #include "proc_darwin.h" | ||||
|  | ||||
| static const unsigned char info_plist[] | ||||
| __attribute__ ((section ("__TEXT,__info_plist"),used)) = | ||||
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | ||||
| "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"" | ||||
| " \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" | ||||
| "<plist version=\"1.0\">\n" | ||||
| "<dict>\n" | ||||
| "  <key>CFBundleIdentifier</key>\n" | ||||
| "  <string>org.dlv</string>\n" | ||||
| "  <key>CFBundleName</key>\n" | ||||
| "  <string>delve</string>\n" | ||||
| "  <key>CFBundleVersion</key>\n" | ||||
| "  <string>1.0</string>\n" | ||||
| "  <key>SecTaskAccess</key>\n" | ||||
| "  <array>\n" | ||||
| "    <string>allowed</string>\n" | ||||
| "    <string>debug</string>\n" | ||||
| "  </array>\n" | ||||
| "</dict>\n" | ||||
| "</plist>\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; | ||||
| } | ||||
							
								
								
									
										511
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,511 @@ | ||||
| package proc | ||||
|  | ||||
| // #include "proc_darwin.h" | ||||
| // #include "threads_darwin.h" | ||||
| // #include "exec_darwin.h" | ||||
| // #include <stdlib.h> | ||||
| 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 | ||||
| } | ||||
							
								
								
									
										54
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_darwin.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #include <sys/types.h> | ||||
| #include <libproc.h> | ||||
| #include <mach/mach.h> | ||||
| #include <mach/mach_vm.h> | ||||
| #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); | ||||
							
								
								
									
										489
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										489
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										672
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										672
									
								
								vendor/github.com/derekparker/delve/pkg/proc/proc_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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() | ||||
| } | ||||
							
								
								
									
										28
									
								
								vendor/github.com/derekparker/delve/pkg/proc/ptrace_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/derekparker/delve/pkg/proc/ptrace_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										96
									
								
								vendor/github.com/derekparker/delve/pkg/proc/ptrace_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								vendor/github.com/derekparker/delve/pkg/proc/ptrace_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/github.com/derekparker/delve/pkg/proc/ptrace_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/derekparker/delve/pkg/proc/ptrace_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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)) | ||||
| } | ||||
							
								
								
									
										231
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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, " ")) | ||||
| } | ||||
							
								
								
									
										367
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers_darwin_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers_darwin_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										329
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers_linux_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers_linux_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										351
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers_windows_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								vendor/github.com/derekparker/delve/pkg/proc/registers_windows_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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") | ||||
| } | ||||
							
								
								
									
										261
									
								
								vendor/github.com/derekparker/delve/pkg/proc/stack.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								vendor/github.com/derekparker/delve/pkg/proc/stack.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										112
									
								
								vendor/github.com/derekparker/delve/pkg/proc/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/derekparker/delve/pkg/proc/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
							
								
								
									
										114
									
								
								vendor/github.com/derekparker/delve/pkg/proc/syscall_windows_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								vendor/github.com/derekparker/delve/pkg/proc/syscall_windows_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										510
									
								
								vendor/github.com/derekparker/delve/pkg/proc/threads.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								vendor/github.com/derekparker/delve/pkg/proc/threads.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
							
								
								
									
										177
									
								
								vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								vendor/github.com/derekparker/delve/pkg/proc/threads_darwin.c
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 Faissal Elamraoui
					Faissal Elamraoui