docs: Move wiki docs into Documentation dir
Going forward, all documentation should be placed in the Documentation directory in the root of the project. This switch allows maintainers to approve updates to documentation before they are committed, as opposed to the pre-existing wiki which anybody could modify. Currently the Documentation directory includes docs on building, usage, and minimal docs around the API. This is just the initial commit, and documentation will continue to improve over time. Some changes have been made (and will continue to be made) to `cmd/dlv` to ensure we can auto-generate documentation for all commands from the newly provided script `scripts/gen-usage-docs.go`, which can be invoked via `go run scripts/gen-usage-docs.go`. Additionally, version has been split into its own package. This was a bit of housekeeping related to the changes made the `cmd/dlv`.
This commit is contained in:
parent
460f0c910c
commit
63a660820e
8
Documentation/README.md
Normal file
8
Documentation/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Delve Documentation
|
||||
|
||||
Documentation for the project will reside in this directory.
|
||||
|
||||
- [Installation](installation)
|
||||
- [Usage](usage)
|
||||
- [API](api)
|
||||
- [Internal](internal)
|
31
Documentation/api/README.md
Normal file
31
Documentation/api/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
# API Documentation
|
||||
|
||||
Delve exposes an API interface so that other programs, mostly IDEs and editors, can interact with Delve programmatically. The API is used by the terminal client, so will always stay up to date in lockstep regardless of new features.
|
||||
|
||||
## Usage
|
||||
|
||||
In order to run Delve in "API mode", simply invoke with one of the standard commands, providing the `--headless` flag, like so:
|
||||
|
||||
```
|
||||
$ dlv debug --headless --log --listen=127.0.0.1:8181
|
||||
```
|
||||
|
||||
This will start the debugger in a non-interactive mode, listening on the specified address, and will enable logging. The last two flags are optional, of course.
|
||||
|
||||
Optionally, you may also specify the `--accept-multiclient` flag if you would like to connect multiple clients to the API.
|
||||
|
||||
You can connect the headless debugger from Delve itself using the `connect` subcommand:
|
||||
|
||||
```
|
||||
$ dlv connect 127.0.0.1:8181
|
||||
```
|
||||
|
||||
This can be useful for remote debugging.
|
||||
|
||||
## API Interfaces
|
||||
|
||||
Delve has been architected in such a way as to allow multiple client/server implementations. All of the "business logic" as it were is abstracted away from the actual client/server implementations, allowing for easy implementation of new API interfaces.
|
||||
|
||||
### Current API Interfaces
|
||||
|
||||
- [JSON-RPC](json-rpc/README.md)
|
3
Documentation/api/json-rpc/README.md
Normal file
3
Documentation/api/json-rpc/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# JSON-RPC interface
|
||||
|
||||
Delve exposes a [JSON-RPC](http://json-rpc.org/) API interface. Here is an (incomplete) [list of language implementations](http://json-rpc.org/wiki/implementations).
|
7
Documentation/installation/README.md
Normal file
7
Documentation/installation/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Installation
|
||||
|
||||
Directions for installing Delve on all supported platforms is provided here. Please note you *must* have Go 1.5 or higher installed. Also, if using Go 1.5 you must set `GO15VENDOREXPERIMENT=1` before attempting to install.
|
||||
|
||||
- [OSX](osx/install.md)
|
||||
- [Linux](linux/install.md)
|
||||
- [Windows](windows/install.md)
|
17
Documentation/installation/linux/install.md
Normal file
17
Documentation/installation/linux/install.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Installation on Linux
|
||||
|
||||
Please use the following steps to build and install Delve on Linux.
|
||||
|
||||
There are two ways to install on Linux. First is the standard `go get` method:
|
||||
|
||||
```
|
||||
go get github.com/derekparker/delve/cmd/dlv
|
||||
```
|
||||
|
||||
Alternatively, you can clone the repo and run:
|
||||
|
||||
```
|
||||
$ make install
|
||||
```
|
||||
|
||||
Note: If you are using Go 1.5 you must set `GO15VENDOREXPERIMENT=1` before continuing. The `GO15VENDOREXPERIMENT` env var simply opts into the [Go 1.5 Vendor Experiment](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo/).
|
54
Documentation/installation/osx/install.md
Normal file
54
Documentation/installation/osx/install.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Installation on OSX
|
||||
|
||||
Please use the following steps to build and install Delve on OSX.
|
||||
|
||||
## 1) Create a self-signed certificate
|
||||
|
||||
You must create a self signed certificate and sign the binary with it:
|
||||
|
||||
* Open application “Keychain Access” (/Applications/Utilities/Keychain Access.app)
|
||||
* Open menu /Keychain Access/Certificate Assistant/Create a Certificate...
|
||||
* Choose a name (dlv-cert in the example), set “Identity Type” to “Self Signed Root”, set “Certificate Type” to “Code Signing” and select the “Let me override defaults”. Click “Continue”. You might want to extend the predefined 365 days period to 3650 days.
|
||||
* Click several times on “Continue” until you get to the “Specify a Location For The Certificate” screen, then set “Keychain to System”.
|
||||
* If you can't store the certificate in the “System” keychain, create it in the “login” keychain, then export it. You can then import it into the “System” keychain.
|
||||
* In keychains select “System”, and you should find your new certificate. Use the context menu for the certificate, select “Get Info”, open the “Trust” item, and set “Code Signing” to “Always Trust”.
|
||||
* [At least on Yosemite:] In keychains select category Keys -> dlv-cert -> right click -> GetInfo -> Access Control -> select "Allow all applications to access this item" -> Save Changes.
|
||||
* You must quit “Keychain Access” application in order to use the certificate and restart “taskgated” service by killing the current running “taskgated” process. Alternatively you can restart your computer.
|
||||
* Run the following: `GO15VENDOREXPERIMENT=1 CERT=dlv-cert make install`, which will install the binary and codesign it.
|
||||
|
||||
|
||||
## 2) Install the binary
|
||||
|
||||
Note: If you are using Go 1.5 you must set `GO15VENDOREXPERIMENT=1` before continuing. The `GO15VENDOREXPERIMENT` env var simply opts into the [Go 1.5 Vendor Experiment](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo/).
|
||||
|
||||
All `make` commands assume a CERT environment variables that contains the name of the cert you created above.
|
||||
|
||||
Now, simply run:
|
||||
|
||||
```
|
||||
$ CERT=mycert make install
|
||||
```
|
||||
|
||||
The Makefile also assumes that `GOPATH` is single-valued, not colon-separated.
|
||||
|
||||
The makefile is only necessary to help facilitate the process of building and codesigning.
|
||||
|
||||
## Notes
|
||||
|
||||
### Eliminating codesign authorization prompt during builds
|
||||
|
||||
If you're prompted for authorization when running `make` using your self-signed certificate, try the following:
|
||||
|
||||
* Open application “Keychain Access” (/Applications/Utilities/Keychain Access.app)
|
||||
* Double-click on the private key corresponding to your self-signed certificate (dlv-cert in the example)
|
||||
* Choose the "Access Control" tab
|
||||
* Click the [+] under "Always allow access by these applications", and choose `/usr/bin/codesign` from the Finder dialog
|
||||
* Click the "Save changes" button
|
||||
|
||||
#### Eliminating "Developer tools access" prompt running delve
|
||||
|
||||
If you are prompted with this when running `dlv`:
|
||||
|
||||
"Developer tools access needs to take control of another process for debugging to continue. Type your password to allow this"
|
||||
|
||||
Try running `DevToolsSecurity -enable` to eliminate the prompt. See `man DevToolsSecurity` for more information.
|
27
Documentation/installation/windows/install.md
Normal file
27
Documentation/installation/windows/install.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Installation on Windows
|
||||
|
||||
Please use the following steps to build and install Delve on Windows.
|
||||
|
||||
If you have a unix-y shell on Windows ([MSYS2](http://sourceforge.net/p/msys2/wiki/MSYS2%20installation/), [CYGWIN](https://cygwin.com/install.html) or other), follow the Linux installation directions.
|
||||
|
||||
From a standard Windows `cmd` shell, use the following steps:
|
||||
|
||||
## 1) Install MinGW
|
||||
|
||||
Install [MinGW-W64](http://sourceforge.net/projects/mingw-w64/) to get a GCC toolchain which is required to [build with CGO on Windows](https://github.com/golang/go/wiki/cgo#windows).
|
||||
|
||||
You should select:
|
||||
|
||||
* Version: Latest available (`5.3.0` at time of writing)
|
||||
* Architecture: `x86_64`
|
||||
* Threads: `posix` (shouldn't actually matter)
|
||||
* Exception: `seh` (shouldn't actually matter)
|
||||
* Build revision: Latest available (`0` at time of writing)
|
||||
|
||||
|
||||
## 2) Make and install the `dlv` binary
|
||||
```
|
||||
$ mingw32-make install
|
||||
```
|
||||
|
||||
Note: If you are using Go 1.5 you must set `GO15VENDOREXPERIMENT=1` before continuing. The `GO15VENDOREXPERIMENT` env var simply opts into the [Go 1.5 Vendor Experiment](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo/).
|
5
Documentation/internal/README.md
Normal file
5
Documentation/internal/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Internal Documentation
|
||||
|
||||
TODO(derekparker)
|
||||
|
||||
This directory will hold documentation around the internals of the debugger and how it works.
|
5
Documentation/usage/README.md
Normal file
5
Documentation/usage/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Using Delve
|
||||
|
||||
You can invoke Delve in multiple ways, depending on your usage needs. Delve makes every attempt to be user-friendly, ensuring the user has to do the least amount of work possible to begin debugging their program.
|
||||
|
||||
Refer to the [main usage document](dlv.md) to further explore commands.
|
0
Documentation/usage/commands.md
Normal file
0
Documentation/usage/commands.md
Normal file
37
Documentation/usage/dlv.md
Normal file
37
Documentation/usage/dlv.md
Normal file
@ -0,0 +1,37 @@
|
||||
## dlv
|
||||
|
||||
Delve is a debugger for the Go programming language.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Delve is a source level debugger for Go programs.
|
||||
|
||||
Delve enables you to interact with your program by controlling the execution of the process,
|
||||
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
|
||||
|
||||
The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv attach](dlv_attach.md) - Attach to running process and begin debugging.
|
||||
* [dlv connect](dlv_connect.md) - Connect to a headless debug server.
|
||||
* [dlv debug](dlv_debug.md) - Compile and begin debugging program.
|
||||
* [dlv exec](dlv_exec.md) - Runs precompiled binary, attaches and begins debug session.
|
||||
* [dlv run](dlv_run.md) - Deprecated command. Use 'debug' instead.
|
||||
* [dlv test](dlv_test.md) - Compile test binary and begin debugging program.
|
||||
* [dlv trace](dlv_trace.md) - Compile and begin tracing program.
|
||||
* [dlv version](dlv_version.md) - Prints version.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
28
Documentation/usage/dlv_attach.md
Normal file
28
Documentation/usage/dlv_attach.md
Normal file
@ -0,0 +1,28 @@
|
||||
## dlv attach
|
||||
|
||||
Attach to running process and begin debugging.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Attach to running process and begin debugging.
|
||||
|
||||
```
|
||||
dlv attach pid
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
28
Documentation/usage/dlv_connect.md
Normal file
28
Documentation/usage/dlv_connect.md
Normal file
@ -0,0 +1,28 @@
|
||||
## dlv connect
|
||||
|
||||
Connect to a headless debug server.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Connect to a headless debug server.
|
||||
|
||||
```
|
||||
dlv connect addr
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
29
Documentation/usage/dlv_debug.md
Normal file
29
Documentation/usage/dlv_debug.md
Normal file
@ -0,0 +1,29 @@
|
||||
## dlv debug
|
||||
|
||||
Compile and begin debugging program.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Compiles your program with optimizations disabled,
|
||||
starts and attaches to it, and enables you to immediately begin debugging your program.
|
||||
|
||||
```
|
||||
dlv debug [package]
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
28
Documentation/usage/dlv_exec.md
Normal file
28
Documentation/usage/dlv_exec.md
Normal file
@ -0,0 +1,28 @@
|
||||
## dlv exec
|
||||
|
||||
Runs precompiled binary, attaches and begins debug session.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Runs precompiled binary, attaches and begins debug session.
|
||||
|
||||
```
|
||||
dlv exec [./path/to/binary]
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
28
Documentation/usage/dlv_run.md
Normal file
28
Documentation/usage/dlv_run.md
Normal file
@ -0,0 +1,28 @@
|
||||
## dlv run
|
||||
|
||||
Deprecated command. Use 'debug' instead.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Deprecated command. Use 'debug' instead.
|
||||
|
||||
```
|
||||
dlv run
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
28
Documentation/usage/dlv_test.md
Normal file
28
Documentation/usage/dlv_test.md
Normal file
@ -0,0 +1,28 @@
|
||||
## dlv test
|
||||
|
||||
Compile test binary and begin debugging program.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Compiles a test binary with optimizations disabled, starts and attaches to it, and enable you to immediately begin debugging your program.
|
||||
|
||||
```
|
||||
dlv test [package]
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
35
Documentation/usage/dlv_trace.md
Normal file
35
Documentation/usage/dlv_trace.md
Normal file
@ -0,0 +1,35 @@
|
||||
## dlv trace
|
||||
|
||||
Compile and begin tracing program.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Trace program execution. Will set a tracepoint on every function matching the provided regular expression and output information when tracepoint is hit.
|
||||
|
||||
```
|
||||
dlv trace [package] regexp
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-p, --pid=0: Pid to attach to.
|
||||
-s, --stack=0: Show stack trace with given depth.
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
28
Documentation/usage/dlv_version.md
Normal file
28
Documentation/usage/dlv_version.md
Normal file
@ -0,0 +1,28 @@
|
||||
## dlv version
|
||||
|
||||
Prints version.
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Prints version.
|
||||
|
||||
```
|
||||
dlv version
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--accept-multiclient[=false]: Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate
|
||||
--build-flags="": Build flags, to be passed to the compiler.
|
||||
--headless[=false]: Run debug server only, in headless mode.
|
||||
--init="": Init file, executed by the terminal client.
|
||||
-l, --listen="localhost:0": Debugging server listen address.
|
||||
--log[=false]: Enable debugging server logging.
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
* [dlv](dlv.md) - Delve is a debugger for the Go programming language.
|
||||
|
||||
###### Auto generated by spf13/cobra on 19-Feb-2016
|
@ -12,11 +12,8 @@ The Github issue tracker is for **bugs** only. Please use the [developer mailing
|
||||
|
||||
### About Delve
|
||||
|
||||
- [Building](https://github.com/derekparker/delve/wiki/Building)
|
||||
- [Usage](https://github.com/derekparker/delve/wiki/Usage)
|
||||
- [Command reference](https://github.com/derekparker/delve/wiki/Commands)
|
||||
- [Installation Tips & Troubleshooting](https://github.com/derekparker/delve/wiki/Tips-&-Troubleshooting)
|
||||
- [Upcoming Features](https://github.com/derekparker/delve/wiki/Upcoming-Features)
|
||||
- [Contributing](https://github.com/derekparker/delve/blob/master/CONTRIBUTING.md)
|
||||
- [Documentation](Documentation)
|
||||
- [Building](Documentation/installation)
|
||||
- [Contributing](CONTRIBUTING.md)
|
||||
|
||||
Delve is a debugger for the Go programming language. The goal of the project is to provide a simple, full featured debugging tool for Go. Delve should be easy to invoke and easy to use. Chances are if you're using a debugger, most likely things aren't going your way. With that in mind, Delve should stay out of your way as much as possible.
|
||||
|
406
cmd/dlv/cmds/commands.go
Normal file
406
cmd/dlv/cmds/commands.go
Normal file
@ -0,0 +1,406 @@
|
||||
package cmds
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/derekparker/delve/config"
|
||||
"github.com/derekparker/delve/service"
|
||||
"github.com/derekparker/delve/service/api"
|
||||
"github.com/derekparker/delve/service/rpc"
|
||||
"github.com/derekparker/delve/terminal"
|
||||
"github.com/derekparker/delve/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Log is whether to log debug statements.
|
||||
Log bool
|
||||
// Headless is whether to run without terminal.
|
||||
Headless bool
|
||||
// AcceptMulti allows multiple clients to connect to the same server
|
||||
AcceptMulti bool
|
||||
// Addr is the debugging server listen address.
|
||||
Addr string
|
||||
// InitFile is the path to initialization file.
|
||||
InitFile string
|
||||
// BuildFlags is the flags passed during compiler invocation.
|
||||
BuildFlags string
|
||||
|
||||
// RootCommand is the root of the command tree.
|
||||
RootCommand *cobra.Command
|
||||
|
||||
traceAttachPid int
|
||||
traceStackDepth int
|
||||
|
||||
conf *config.Config
|
||||
)
|
||||
|
||||
const (
|
||||
debugname = "debug"
|
||||
testdebugname = "debug.test"
|
||||
)
|
||||
|
||||
const dlvCommandLongDesc = `Delve is a source level debugger for Go programs.
|
||||
|
||||
Delve enables you to interact with your program by controlling the execution of the process,
|
||||
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
|
||||
|
||||
The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
|
||||
`
|
||||
|
||||
// New returns an initialized command tree.
|
||||
func New() *cobra.Command {
|
||||
// Config setup and load.
|
||||
conf = config.LoadConfig()
|
||||
buildFlagsDefault := ""
|
||||
if runtime.GOOS == "windows" {
|
||||
// Work-around for https://github.com/golang/go/issues/13154
|
||||
buildFlagsDefault = "-ldflags=-linkmode internal"
|
||||
}
|
||||
|
||||
// Main dlv root command.
|
||||
RootCommand = &cobra.Command{
|
||||
Use: "dlv",
|
||||
Short: "Delve is a debugger for the Go programming language.",
|
||||
Long: dlvCommandLongDesc,
|
||||
}
|
||||
|
||||
RootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.")
|
||||
RootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.")
|
||||
RootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.")
|
||||
RootCommand.PersistentFlags().BoolVarP(&AcceptMulti, "accept-multiclient", "", false, "Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate")
|
||||
RootCommand.PersistentFlags().StringVar(&InitFile, "init", "", "Init file, executed by the terminal client.")
|
||||
RootCommand.PersistentFlags().StringVar(&BuildFlags, "build-flags", buildFlagsDefault, "Build flags, to be passed to the compiler.")
|
||||
|
||||
// 'version' subcommand.
|
||||
versionCommand := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Prints version.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("Delve Debugger\n%s\n", version.DelveVersion)
|
||||
},
|
||||
}
|
||||
RootCommand.AddCommand(versionCommand)
|
||||
|
||||
// Deprecated 'run' subcommand.
|
||||
runCommand := &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Deprecated command. Use 'debug' instead.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("This command is deprecated, please use 'debug' instead.")
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
RootCommand.AddCommand(runCommand)
|
||||
|
||||
// 'debug' subcommand.
|
||||
debugCommand := &cobra.Command{
|
||||
Use: "debug [package]",
|
||||
Short: "Compile and begin debugging program.",
|
||||
Long: `Compiles your program with optimizations disabled,
|
||||
starts and attaches to it, and enables you to immediately begin debugging your program.`,
|
||||
Run: debugCmd,
|
||||
}
|
||||
RootCommand.AddCommand(debugCommand)
|
||||
|
||||
// 'exec' subcommand.
|
||||
execCommand := &cobra.Command{
|
||||
Use: "exec [./path/to/binary]",
|
||||
Short: "Runs precompiled binary, attaches and begins debug session.",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("you must provide a path to a binary")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
os.Exit(execute(0, args, conf))
|
||||
},
|
||||
}
|
||||
RootCommand.AddCommand(execCommand)
|
||||
|
||||
// 'trace' subcommand.
|
||||
traceCommand := &cobra.Command{
|
||||
Use: "trace [package] regexp",
|
||||
Short: "Compile and begin tracing program.",
|
||||
Long: "Trace program execution. Will set a tracepoint on every function matching the provided regular expression and output information when tracepoint is hit.",
|
||||
Run: traceCmd,
|
||||
}
|
||||
traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
|
||||
traceCommand.Flags().IntVarP(&traceStackDepth, "stack", "s", 0, "Show stack trace with given depth.")
|
||||
RootCommand.AddCommand(traceCommand)
|
||||
|
||||
// 'test' subcommand.
|
||||
testCommand := &cobra.Command{
|
||||
Use: "test [package]",
|
||||
Short: "Compile test binary and begin debugging program.",
|
||||
Long: `Compiles a test binary with optimizations disabled, starts and attaches to it, and enable you to immediately begin debugging your program.`,
|
||||
Run: testCmd,
|
||||
}
|
||||
RootCommand.AddCommand(testCommand)
|
||||
|
||||
// 'attach' subcommand.
|
||||
attachCommand := &cobra.Command{
|
||||
Use: "attach pid",
|
||||
Short: "Attach to running process and begin debugging.",
|
||||
Long: "Attach to running process and begin debugging.",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("you must provide a PID")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: attachCmd,
|
||||
}
|
||||
RootCommand.AddCommand(attachCommand)
|
||||
|
||||
// 'connect' subcommand.
|
||||
connectCommand := &cobra.Command{
|
||||
Use: "connect addr",
|
||||
Short: "Connect to a headless debug server.",
|
||||
Long: "Connect to a headless debug server.",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("you must provide an address as the first argument")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: connectCmd,
|
||||
}
|
||||
RootCommand.AddCommand(connectCommand)
|
||||
|
||||
return RootCommand
|
||||
}
|
||||
|
||||
func debugCmd(cmd *cobra.Command, args []string) {
|
||||
status := func() int {
|
||||
var pkg string
|
||||
dlvArgs, targetArgs := splitArgs(cmd, args)
|
||||
|
||||
if len(dlvArgs) > 0 {
|
||||
pkg = args[0]
|
||||
}
|
||||
err := gobuild(debugname, pkg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return 1
|
||||
}
|
||||
fp, err := filepath.Abs("./" + debugname)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return 1
|
||||
}
|
||||
defer os.Remove(fp)
|
||||
|
||||
processArgs := append([]string{"./" + debugname}, targetArgs...)
|
||||
return execute(0, processArgs, conf)
|
||||
}()
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func traceCmd(cmd *cobra.Command, args []string) {
|
||||
status := func() int {
|
||||
var regexp string
|
||||
var processArgs []string
|
||||
|
||||
dlvArgs, targetArgs := splitArgs(cmd, args)
|
||||
|
||||
if traceAttachPid == 0 {
|
||||
var pkg string
|
||||
switch len(dlvArgs) {
|
||||
case 1:
|
||||
regexp = args[0]
|
||||
case 2:
|
||||
pkg = args[0]
|
||||
regexp = args[1]
|
||||
}
|
||||
if err := gobuild(debugname, pkg); err != nil {
|
||||
return 1
|
||||
}
|
||||
defer os.Remove("./" + debugname)
|
||||
|
||||
processArgs = append([]string{"./" + debugname}, targetArgs...)
|
||||
}
|
||||
// Make a TCP listener
|
||||
listener, err := net.Listen("tcp", Addr)
|
||||
if err != nil {
|
||||
fmt.Printf("couldn't start listener: %s\n", err)
|
||||
return 1
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
// Create and start a debug server
|
||||
server := rpc.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: processArgs,
|
||||
AttachPid: traceAttachPid,
|
||||
}, Log)
|
||||
if err := server.Run(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
client := rpc.NewClient(listener.Addr().String())
|
||||
funcs, err := client.ListFunctions(regexp)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
for i := range funcs {
|
||||
_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true, Line: -1, Stacktrace: traceStackDepth})
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
cmds := terminal.DebugCommands(client)
|
||||
cmd := cmds.Find("continue")
|
||||
t := terminal.New(client, nil)
|
||||
defer t.Close()
|
||||
err = cmd(t, "")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}()
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func testCmd(cmd *cobra.Command, args []string) {
|
||||
status := func() int {
|
||||
var pkg string
|
||||
dlvArgs, targetArgs := splitArgs(cmd, args)
|
||||
|
||||
if len(dlvArgs) > 0 {
|
||||
pkg = args[0]
|
||||
}
|
||||
err := gotestbuild(pkg)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
defer os.Remove("./" + testdebugname)
|
||||
processArgs := append([]string{"./" + testdebugname}, targetArgs...)
|
||||
|
||||
return execute(0, processArgs, conf)
|
||||
}()
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func attachCmd(cmd *cobra.Command, args []string) {
|
||||
pid, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(execute(pid, nil, conf))
|
||||
}
|
||||
|
||||
func connectCmd(cmd *cobra.Command, args []string) {
|
||||
addr := args[0]
|
||||
if addr == "" {
|
||||
fmt.Fprintf(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(connect(addr, conf))
|
||||
}
|
||||
|
||||
func splitArgs(cmd *cobra.Command, args []string) ([]string, []string) {
|
||||
if cmd.ArgsLenAtDash() >= 0 {
|
||||
return args[:cmd.ArgsLenAtDash()], args[cmd.ArgsLenAtDash():]
|
||||
}
|
||||
return args, []string{}
|
||||
}
|
||||
|
||||
func connect(addr string, conf *config.Config) int {
|
||||
// Create and start a terminal - attach to running instance
|
||||
var client service.Client
|
||||
client = rpc.NewClient(addr)
|
||||
term := terminal.New(client, conf)
|
||||
status, err := term.Run()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func execute(attachPid int, processArgs []string, conf *config.Config) int {
|
||||
// Make a TCP listener
|
||||
listener, err := net.Listen("tcp", Addr)
|
||||
if err != nil {
|
||||
fmt.Printf("couldn't start listener: %s\n", err)
|
||||
return 1
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
if Headless && (InitFile != "") {
|
||||
fmt.Fprintf(os.Stderr, "Warning: init file ignored\n")
|
||||
}
|
||||
|
||||
// Create and start a debugger server
|
||||
server := rpc.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: processArgs,
|
||||
AttachPid: attachPid,
|
||||
AcceptMulti: AcceptMulti,
|
||||
}, Log)
|
||||
if err := server.Run(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
|
||||
var status int
|
||||
if Headless {
|
||||
ch := make(chan os.Signal)
|
||||
signal.Notify(ch, syscall.SIGINT)
|
||||
<-ch
|
||||
err = server.Stop(true)
|
||||
} else {
|
||||
// Create and start a terminal
|
||||
var client service.Client
|
||||
client = rpc.NewClient(listener.Addr().String())
|
||||
term := terminal.New(client, conf)
|
||||
term.InitFile = InitFile
|
||||
status, err = term.Run()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func gobuild(debugname, pkg string) error {
|
||||
args := []string{"-gcflags", "-N -l", "-o", debugname}
|
||||
if BuildFlags != "" {
|
||||
args = append(args, BuildFlags)
|
||||
}
|
||||
args = append(args, pkg)
|
||||
return gocommand("build", args...)
|
||||
}
|
||||
|
||||
func gotestbuild(pkg string) error {
|
||||
args := []string{"-gcflags", "-N -l", "-c", "-o", testdebugname}
|
||||
if BuildFlags != "" {
|
||||
args = append(args, BuildFlags)
|
||||
}
|
||||
args = append(args, pkg)
|
||||
return gocommand("test", args...)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
408
cmd/dlv/main.go
408
cmd/dlv/main.go
@ -1,410 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/derekparker/delve/config"
|
||||
"github.com/derekparker/delve/service"
|
||||
"github.com/derekparker/delve/service/api"
|
||||
"github.com/derekparker/delve/service/rpc"
|
||||
"github.com/derekparker/delve/terminal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/derekparker/delve/cmd/dlv/cmds"
|
||||
"github.com/derekparker/delve/version"
|
||||
)
|
||||
|
||||
const (
|
||||
version = "0.11.0-alpha"
|
||||
debugname = "debug"
|
||||
testdebugname = "debug.test"
|
||||
)
|
||||
|
||||
var (
|
||||
// Log is whether to log debug statements.
|
||||
Log bool
|
||||
// Headless is whether to run without terminal.
|
||||
Headless bool
|
||||
// Allows multiple clients to connect to the same server
|
||||
AcceptMulti bool
|
||||
// Addr is the debugging server listen address.
|
||||
Addr string
|
||||
// InitFile is the path to initialization file.
|
||||
InitFile string
|
||||
// BuildFlags is the flags passed during compiler invocation.
|
||||
BuildFlags string
|
||||
// Build is the current git hash.
|
||||
Build string
|
||||
|
||||
traceAttachPid int
|
||||
traceStackDepth int
|
||||
|
||||
conf *config.Config
|
||||
|
||||
rootCommand *cobra.Command
|
||||
)
|
||||
|
||||
const dlvCommandLongDesc = `Delve is a source level debugger for Go programs.
|
||||
|
||||
Delve enables you to interact with your program by controlling the execution of the process,
|
||||
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
|
||||
|
||||
The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
|
||||
`
|
||||
|
||||
func init() {
|
||||
buildFlagsDefault := ""
|
||||
if runtime.GOOS == "windows" {
|
||||
// Work-around for https://github.com/golang/go/issues/13154
|
||||
buildFlagsDefault = "-ldflags=-linkmode internal"
|
||||
}
|
||||
|
||||
// Main dlv root command.
|
||||
rootCommand = &cobra.Command{
|
||||
Use: "dlv",
|
||||
Short: "Delve is a debugger for the Go programming language.",
|
||||
Long: dlvCommandLongDesc,
|
||||
}
|
||||
|
||||
rootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.")
|
||||
rootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.")
|
||||
rootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.")
|
||||
rootCommand.PersistentFlags().BoolVarP(&AcceptMulti, "accept-multiclient", "", false, "Allows a headless server to accept multiple client connection. Note that the server API is not reentrant and clients will have to coordinate")
|
||||
rootCommand.PersistentFlags().StringVar(&InitFile, "init", "", "Init file, executed by the terminal client.")
|
||||
rootCommand.PersistentFlags().StringVar(&BuildFlags, "build-flags", buildFlagsDefault, "Build flags, to be passed to the compiler.")
|
||||
|
||||
// 'version' subcommand.
|
||||
versionCommand := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Prints version.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("Delve Debugger\nVersion: %s\nBuild: %s\n", version, Build)
|
||||
},
|
||||
}
|
||||
rootCommand.AddCommand(versionCommand)
|
||||
|
||||
// Deprecated 'run' subcommand.
|
||||
runCommand := &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Deprecated command. Use 'debug' instead.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("This command is deprecated, please use 'debug' instead.")
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
rootCommand.AddCommand(runCommand)
|
||||
|
||||
// 'debug' subcommand.
|
||||
debugCommand := &cobra.Command{
|
||||
Use: "debug [package]",
|
||||
Short: "Compile and begin debugging program.",
|
||||
Long: `Compiles your program with optimizations disabled,
|
||||
starts and attaches to it, and enables you to immediately begin debugging your program.`,
|
||||
Run: debugCmd,
|
||||
}
|
||||
rootCommand.AddCommand(debugCommand)
|
||||
|
||||
// 'exec' subcommand.
|
||||
execCommand := &cobra.Command{
|
||||
Use: "exec [./path/to/binary]",
|
||||
Short: "Runs precompiled binary, attaches and begins debug session.",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("you must provide a path to a binary")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
os.Exit(execute(0, args, conf))
|
||||
},
|
||||
}
|
||||
rootCommand.AddCommand(execCommand)
|
||||
|
||||
// 'trace' subcommand.
|
||||
traceCommand := &cobra.Command{
|
||||
Use: "trace [package] regexp",
|
||||
Short: "Compile and begin tracing program.",
|
||||
Long: "Trace program execution. Will set a tracepoint on every function matching the provided regular expression and output information when tracepoint is hit.",
|
||||
Run: traceCmd,
|
||||
}
|
||||
traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
|
||||
traceCommand.Flags().IntVarP(&traceStackDepth, "stack", "s", 0, "Show stack trace with given depth.")
|
||||
rootCommand.AddCommand(traceCommand)
|
||||
|
||||
// 'test' subcommand.
|
||||
testCommand := &cobra.Command{
|
||||
Use: "test [package]",
|
||||
Short: "Compile test binary and begin debugging program.",
|
||||
Long: `Compiles a test binary with optimizations disabled, starts and attaches to it, and enable you to immediately begin debugging your program.`,
|
||||
Run: testCmd,
|
||||
}
|
||||
rootCommand.AddCommand(testCommand)
|
||||
|
||||
// 'attach' subcommand.
|
||||
attachCommand := &cobra.Command{
|
||||
Use: "attach pid",
|
||||
Short: "Attach to running process and begin debugging.",
|
||||
Long: "Attach to running process and begin debugging.",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("you must provide a PID")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: attachCmd,
|
||||
}
|
||||
rootCommand.AddCommand(attachCommand)
|
||||
|
||||
// 'connect' subcommand.
|
||||
connectCommand := &cobra.Command{
|
||||
Use: "connect addr",
|
||||
Short: "Connect to a headless debug server.",
|
||||
Long: "Connect to a headless debug server.",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("you must provide an address as the first argument")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: connectCmd,
|
||||
}
|
||||
rootCommand.AddCommand(connectCommand)
|
||||
}
|
||||
// Build is the git sha of this binaries build.
|
||||
var Build string
|
||||
|
||||
func main() {
|
||||
// Config setup and load.
|
||||
conf = config.LoadConfig()
|
||||
|
||||
rootCommand.Execute()
|
||||
}
|
||||
|
||||
func debugCmd(cmd *cobra.Command, args []string) {
|
||||
status := func() int {
|
||||
var pkg string
|
||||
dlvArgs, targetArgs := splitArgs(cmd, args)
|
||||
|
||||
if len(dlvArgs) > 0 {
|
||||
pkg = args[0]
|
||||
}
|
||||
err := gobuild(debugname, pkg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return 1
|
||||
}
|
||||
fp, err := filepath.Abs("./" + debugname)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return 1
|
||||
}
|
||||
defer os.Remove(fp)
|
||||
|
||||
processArgs := append([]string{"./" + debugname}, targetArgs...)
|
||||
return execute(0, processArgs, conf)
|
||||
}()
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func traceCmd(cmd *cobra.Command, args []string) {
|
||||
status := func() int {
|
||||
var regexp string
|
||||
var processArgs []string
|
||||
|
||||
dlvArgs, targetArgs := splitArgs(cmd, args)
|
||||
|
||||
if traceAttachPid == 0 {
|
||||
var pkg string
|
||||
switch len(dlvArgs) {
|
||||
case 1:
|
||||
regexp = args[0]
|
||||
case 2:
|
||||
pkg = args[0]
|
||||
regexp = args[1]
|
||||
}
|
||||
if err := gobuild(debugname, pkg); err != nil {
|
||||
return 1
|
||||
}
|
||||
defer os.Remove("./" + debugname)
|
||||
|
||||
processArgs = append([]string{"./" + debugname}, targetArgs...)
|
||||
}
|
||||
// Make a TCP listener
|
||||
listener, err := net.Listen("tcp", Addr)
|
||||
if err != nil {
|
||||
fmt.Printf("couldn't start listener: %s\n", err)
|
||||
return 1
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
// Create and start a debug server
|
||||
server := rpc.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: processArgs,
|
||||
AttachPid: traceAttachPid,
|
||||
}, Log)
|
||||
if err := server.Run(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
client := rpc.NewClient(listener.Addr().String())
|
||||
funcs, err := client.ListFunctions(regexp)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
for i := range funcs {
|
||||
_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true, Line: -1, Stacktrace: traceStackDepth})
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
cmds := terminal.DebugCommands(client)
|
||||
cmd := cmds.Find("continue")
|
||||
t := terminal.New(client, nil)
|
||||
defer t.Close()
|
||||
err = cmd(t, "")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}()
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func testCmd(cmd *cobra.Command, args []string) {
|
||||
status := func() int {
|
||||
var pkg string
|
||||
dlvArgs, targetArgs := splitArgs(cmd, args)
|
||||
|
||||
if len(dlvArgs) > 0 {
|
||||
pkg = args[0]
|
||||
}
|
||||
err := gotestbuild(pkg)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
defer os.Remove("./" + testdebugname)
|
||||
processArgs := append([]string{"./" + testdebugname}, targetArgs...)
|
||||
|
||||
return execute(0, processArgs, conf)
|
||||
}()
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func attachCmd(cmd *cobra.Command, args []string) {
|
||||
pid, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(execute(pid, nil, conf))
|
||||
}
|
||||
|
||||
func connectCmd(cmd *cobra.Command, args []string) {
|
||||
addr := args[0]
|
||||
if addr == "" {
|
||||
fmt.Fprintf(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(connect(addr, conf))
|
||||
}
|
||||
|
||||
func splitArgs(cmd *cobra.Command, args []string) ([]string, []string) {
|
||||
if cmd.ArgsLenAtDash() >= 0 {
|
||||
return args[:cmd.ArgsLenAtDash()], args[cmd.ArgsLenAtDash():]
|
||||
}
|
||||
return args, []string{}
|
||||
}
|
||||
|
||||
func connect(addr string, conf *config.Config) int {
|
||||
// Create and start a terminal - attach to running instance
|
||||
var client service.Client
|
||||
client = rpc.NewClient(addr)
|
||||
term := terminal.New(client, conf)
|
||||
status, err := term.Run()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func execute(attachPid int, processArgs []string, conf *config.Config) int {
|
||||
// Make a TCP listener
|
||||
listener, err := net.Listen("tcp", Addr)
|
||||
if err != nil {
|
||||
fmt.Printf("couldn't start listener: %s\n", err)
|
||||
return 1
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
if Headless && (InitFile != "") {
|
||||
fmt.Fprintf(os.Stderr, "Warning: init file ignored\n")
|
||||
}
|
||||
|
||||
// Create and start a debugger server
|
||||
server := rpc.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: processArgs,
|
||||
AttachPid: attachPid,
|
||||
AcceptMulti: AcceptMulti,
|
||||
}, Log)
|
||||
if err := server.Run(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
|
||||
var status int
|
||||
if Headless {
|
||||
ch := make(chan os.Signal)
|
||||
signal.Notify(ch, syscall.SIGINT)
|
||||
<-ch
|
||||
err = server.Stop(true)
|
||||
} else {
|
||||
// Create and start a terminal
|
||||
var client service.Client
|
||||
client = rpc.NewClient(listener.Addr().String())
|
||||
term := terminal.New(client, conf)
|
||||
term.InitFile = InitFile
|
||||
status, err = term.Run()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func gobuild(debugname, pkg string) error {
|
||||
args := []string{"-gcflags", "-N -l", "-o", debugname}
|
||||
if BuildFlags != "" {
|
||||
args = append(args, BuildFlags)
|
||||
}
|
||||
args = append(args, pkg)
|
||||
return gocommand("build", args...)
|
||||
}
|
||||
|
||||
func gotestbuild(pkg string) error {
|
||||
args := []string{"-gcflags", "-N -l", "-c", "-o", testdebugname}
|
||||
if BuildFlags != "" {
|
||||
args = append(args, BuildFlags)
|
||||
}
|
||||
args = append(args, pkg)
|
||||
return gocommand("test", args...)
|
||||
}
|
||||
|
||||
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()
|
||||
version.DelveVersion.Build = Build
|
||||
cmds.New().Execute()
|
||||
}
|
||||
|
10
scripts/gen-usage-docs.go
Normal file
10
scripts/gen-usage-docs.go
Normal file
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/derekparker/delve/cmd/dlv/cmds"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
doc.GenMarkdownTree(cmds.New(), "./Documentation/usage")
|
||||
}
|
21
version/version.go
Normal file
21
version/version.go
Normal file
@ -0,0 +1,21 @@
|
||||
package version
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Version represents the current version of Delve.
|
||||
type Version struct {
|
||||
Major string
|
||||
Minor string
|
||||
Patch string
|
||||
Metadata string
|
||||
Build string
|
||||
}
|
||||
|
||||
var (
|
||||
// DelveVersion is the current version of Delve.
|
||||
DelveVersion = Version{Major: "0", Minor: "11", Patch: "0", Metadata: "alpha"}
|
||||
)
|
||||
|
||||
func (v Version) String() string {
|
||||
return fmt.Sprintf("Version: %s.%s.%s-%s\nBuild: %s", v.Major, v.Minor, v.Patch, v.Metadata, v.Build)
|
||||
}
|
Loading…
Reference in New Issue
Block a user