Repository: go-delve/delve
Pull request #1997 (2020-04-08 09:11:24)

proc: better support for C pointers
```
proc: better support for C pointers

- treat C pointers as arrays
- print 'char *' variables as strings

proc: fix findCompileUnitForOffset when plugins are used

Splits the compileUnits slice between images so that we can search for
an offset inside the debug info of a specific image file.

```


aarzilli: No longer WIP.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f48e1f0f..32512883 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,38 @@
 All notable changes to this project will be documented in this file.
 This project adheres to Semantic Versioning.
 
-All changes mention the author, unless contributed by me (@derekparker).
+## [1.4.1] 2020-05-22
+
+### Added
+
+- Support for linux/386 added (@chainhelen)
+- DAP server initial release (@polinasok, @eliben, @hyangah)
+- New command `examinemem` (or `x`) allows users to examine raw memory (@chainhelen)
+- New command `display` allows users to print value of an expression every time the program stops (@aarzilli)
+- New flag `--tty` allows users to supply a TTY for the debugged program to use (@derekparker)
+- Coredump support added for Arm64 (@ossdev07)
+- Ability to print goroutine labels (@aarzilli)
+- Allow printing registers for arbitrary stack frames (@aarzilli)
+- Add `disassemble-flavor` to config to specify assembly syntax (@chainhelen)
+
+### Fixed
+
+- Allow function calls on non-struct types (@derekparker)
+- Dwarf line parsing bug fix (@klemens-morgenstern)
+- Improved error message when building Delve on unsupported systems (@aarzilli)
+- Improved error message when trying to execute a binary in an invalid format for host system (@derekparker)
+- Fix panic in Delve when using `call` command with some invalid input (@chainhelen)
+
+### Changed
+
+- Improved output from `dlv trace` and `trace` REPL commands (@derekparker)
+- Conditional breakpoint performance improvements (@aarzilli)
+- Thread register loading performance improvement on gdbserial backend (@derekparker)
+- Reduce default log level to error (@aarzilli)
+- Linux memory read/write optimization using process_vm_read/write (@cuviper)
+- Terminal output of commands divided into categories (@aarzilli)
+- Use less permissive file settings on history file (@derekparker)
+- Autogenerated interface method calls wrappers now automatically stepped through (@aarzilli)
 
 ## [1.4.0] 2020-02-11
 
diff --git a/Documentation/cli/README.md b/Documentation/cli/README.md
index 0eac6dd8..ea721fd6 100644
--- a/Documentation/cli/README.md
+++ b/Documentation/cli/README.md
@@ -13,6 +13,7 @@ Command | Description
 [call](#call) | Resumes process, injecting a function call (EXPERIMENTAL!!!)
 [continue](#continue) | Run until breakpoint or program termination.
 [next](#next) | Step over to next source line.
+[rebuild](#rebuild) | Rebuild the target executable and restarts it. It does not work if the executable was not built by delve.
 [restart](#restart) | Restart process.
 [rev](#rev) | Reverses the execution of the target program for the command specified.
 [rewind](#rewind) | Run backwards until breakpoint or program termination.
@@ -394,6 +395,10 @@ See [Documentation/cli/expr.md](//github.com/go-delve/delve/tree/master/Document
 
 Aliases: p
 
+## rebuild
+Rebuild the target executable and restarts it. It does not work if the executable was not built by delve.
+
+
 ## regs
 Print contents of CPU registers.
 
diff --git a/Documentation/cli/expr.md b/Documentation/cli/expr.md
index 0b0105b5..fcf027f0 100644
--- a/Documentation/cli/expr.md
+++ b/Documentation/cli/expr.md
@@ -106,3 +106,7 @@ Packages with the same name can be disambiguated by using the full package path.
 (dlv) p "some/package".A
 (dlv) p "some/other/package".A
 ```
+
+# Pointers in Cgo
+
+Char pointers are always treated as NUL terminated strings, both indexing and the slice operator can be applied to them. Other C pointers can also be used similarly to Go slices, with indexing and the slice operator. In both of these cases it is up to the user to respect array bounds.
diff --git a/Documentation/cli/starlark.md b/Documentation/cli/starlark.md
index 1de8a5ff..ea64a6ce 100644
--- a/Documentation/cli/starlark.md
+++ b/Documentation/cli/starlark.md
@@ -51,7 +51,7 @@ threads() | Equivalent to API call [ListThreads](https://godoc.org/github.com/go
 types(Filter) | Equivalent to API call [ListTypes](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListTypes)
 process_pid() | Equivalent to API call [ProcessPid](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ProcessPid)
 recorded() | Equivalent to API call [Recorded](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Recorded)
-restart(Position, ResetArgs, NewArgs, Rerecord) | Equivalent to API call [Restart](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Restart)
+restart(Position, ResetArgs, NewArgs, Rerecord, Rebuild) | Equivalent to API call [Restart](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Restart)
 set_expr(Scope, Symbol, Value) | Equivalent to API call [Set](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Set)
 stacktrace(Id, Depth, Full, Defers, Opts, Cfg) | Equivalent to API call [Stacktrace](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Stacktrace)
 state(NonBlocking) | Equivalent to API call [State](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.State)
diff --git a/README.md b/README.md
index 55b50558..a8824739 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@
 [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/go-delve/delve/master/LICENSE)
 [![GoDoc](https://godoc.org/github.com/go-delve/delve?status.svg)](https://godoc.org/github.com/go-delve/delve)
 [![Build Status](https://travis-ci.org/go-delve/delve.svg?branch=master)](https://travis-ci.org/go-delve/delve)
-[![Build status](https://ci.appveyor.com/api/projects/status/0v8r99smxost466s/branch/master?svg=true)](https://ci.appveyor.com/project/derekparker/delve-facy3/branch/master)
 
 The GitHub issue tracker is for **bugs** only. Please use the [developer mailing list](https://groups.google.com/forum/#!forum/delve-dev) for any feature proposals and discussions.
 
diff --git a/_fixtures/issue2023.go b/_fixtures/issue2023.go
new file mode 100644
index 00000000..b8ab8448
--- /dev/null
+++ b/_fixtures/issue2023.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+func A() {
+	fmt.Printf("hello delve\n")
+}
+
+func main() {
+	count := 0
+	for {
+		A()
+		time.Sleep(time.Millisecond * time.Duration(100))
+		if count >= 30 {
+			break
+		}
+		count++
+	}
+}
diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go
index 081c4f6e..e26bacf9 100644
--- a/cmd/dlv/cmds/commands.go
+++ b/cmd/dlv/cmds/commands.go
@@ -210,7 +210,7 @@ or later, -gcflags="-N -l" on earlier versions of Go.`,
 			return nil
 		},
 		Run: func(cmd *cobra.Command, args []string) {
-			os.Exit(execute(0, args, conf, "", executingExistingFile))
+			os.Exit(execute(0, args, conf, "", debugger.ExecutingExistingFile, args, buildFlags))
 		},
 	}
 	execCommand.Flags().StringVar(&tty, "tty", "", "TTY to use for the target program")
@@ -312,7 +312,7 @@ https://github.com/mozilla/rr
 			},
 			Run: func(cmd *cobra.Command, args []string) {
 				backend = "rr"
-				os.Exit(execute(0, []string{}, conf, args[0], executingOther))
+				os.Exit(execute(0, []string{}, conf, args[0], debugger.ExecutingOther, args, buildFlags))
 			},
 		}
 		rootCommand.AddCommand(replayCommand)
@@ -441,7 +441,7 @@ func debugCmd(cmd *cobra.Command, args []string) {
 		}
 		defer gobuild.Remove(debugname)
 		processArgs := append([]string{debugname}, targetArgs...)
-		return execute(0, processArgs, conf, "", executingGeneratedFile)
+		return execute(0, processArgs, conf, "", debugger.ExecutingGeneratedFile, dlvArgs, buildFlags)
 	}()
 	os.Exit(status)
 }
@@ -466,20 +466,19 @@ func traceCmd(cmd *cobra.Command, args []string) {
 		var processArgs []string
 
 		dlvArgs, targetArgs := splitArgs(cmd, args)
+		var dlvArgsLen = len(dlvArgs)
+		if dlvArgsLen == 1 {
+			regexp = args[0]
+			dlvArgs = dlvArgs[0:0]
+		} else if dlvArgsLen >= 2 {
+			regexp = dlvArgs[dlvArgsLen-1]
+			dlvArgs = dlvArgs[:dlvArgsLen-1]
+		}
 
 		if traceAttachPid == 0 {
-			var dlvArgsLen = len(dlvArgs)
-
-			if dlvArgsLen == 1 {
-				regexp = args[0]
-				dlvArgs = dlvArgs[0:0]
-			} else if dlvArgsLen >= 2 {
-				if traceExecFile != "" {
-					fmt.Fprintln(os.Stderr, "Cannot specify package when using exec.")
-					return 1
-				}
-				regexp = dlvArgs[dlvArgsLen-1]
-				dlvArgs = dlvArgs[:dlvArgsLen-1]
+			if dlvArgsLen >= 2 && traceExecFile != "" {
+				fmt.Fprintln(os.Stderr, "Cannot specify package when using exec.")
+				return 1
 			}
 
 			debugname := traceExecFile
@@ -592,7 +591,7 @@ func testCmd(cmd *cobra.Command, args []string) {
 		defer gobuild.Remove(debugname)
 		processArgs := append([]string{debugname}, targetArgs...)
 
-		return execute(0, processArgs, conf, "", executingGeneratedTest)
+		return execute(0, processArgs, conf, "", debugger.ExecutingGeneratedTest, dlvArgs, buildFlags)
 	}()
 	os.Exit(status)
 }
@@ -603,11 +602,11 @@ func attachCmd(cmd *cobra.Command, args []string) {
 		fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
 		os.Exit(1)
 	}
-	os.Exit(execute(pid, args[1:], conf, "", executingOther))
+	os.Exit(execute(pid, args[1:], conf, "", debugger.ExecutingOther, args, buildFlags))
 }
 
 func coreCmd(cmd *cobra.Command, args []string) {
-	os.Exit(execute(0, []string{args[0]}, conf, args[1], executingOther))
+	os.Exit(execute(0, []string{args[0]}, conf, args[1], debugger.ExecutingOther, args, buildFlags))
 }
 
 func connectCmd(cmd *cobra.Command, args []string) {
@@ -616,7 +615,7 @@ func connectCmd(cmd *cobra.Command, args []string) {
 		fmt.Fprint(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
 		os.Exit(1)
 	}
-	os.Exit(connect(addr, nil, conf, executingOther))
+	os.Exit(connect(addr, nil, conf, debugger.ExecutingOther))
 }
 
 // waitForDisconnectSignal is a blocking function that waits for either
@@ -657,7 +656,7 @@ func splitArgs(cmd *cobra.Command, args []string) ([]string, []string) {
 	return args, []string{}
 }
 
-func connect(addr string, clientConn net.Conn, conf *config.Config, kind executeKind) int {
+func connect(addr string, clientConn net.Conn, conf *config.Config, kind debugger.ExecuteKind) int {
 	// Create and start a terminal - attach to running instance
 	var client *rpc2.RPCClient
 	if clientConn != nil {
@@ -688,16 +687,7 @@ func connect(addr string, clientConn net.Conn, conf *config.Config, kind execute
 	return status
 }
 
-type executeKind int
-
-const (
-	executingExistingFile = executeKind(iota)
-	executingGeneratedFile
-	executingGeneratedTest
-	executingOther
-)
-
-func execute(attachPid int, processArgs []string, conf *config.Config, coreFile string, kind executeKind) int {
+func execute(attachPid int, processArgs []string, conf *config.Config, coreFile string, kind debugger.ExecuteKind, dlvArgs []string, buildFlags string) int {
 	if err := logflags.Setup(log, logOutput, logDest); err != nil {
 		fmt.Fprintf(os.Stderr, "%v\n", err)
 		return 1
@@ -761,6 +751,9 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile
 				Backend:              backend,
 				CoreFile:             coreFile,
 				Foreground:           headless && tty == "",
+				Packages:             dlvArgs,
+				BuildFlags:           buildFlags,
+				ExecuteKind:          kind,
 				DebugInfoDirectories: conf.DebugInfoDirectories,
 				CheckGoVersion:       checkGoVersion,
 				TTY:                  tty,
@@ -774,10 +767,10 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile
 	if err := server.Run(); err != nil {
 		if err == api.ErrNotExecutable {
 			switch kind {
-			case executingGeneratedFile:
+			case debugger.ExecutingGeneratedFile:
 				fmt.Fprintln(os.Stderr, "Can not debug non-main package")
 				return 1
-			case executingExistingFile:
+			case debugger.ExecutingExistingFile:
 				fmt.Fprintf(os.Stderr, "%s is not executable\n", processArgs[0])
 				return 1
 			default:
diff --git a/go.mod b/go.mod
index 4de1944f..bfd00bf0 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,6 @@ require (
 	github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561
 	github.com/mattn/go-isatty v0.0.3
 	github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b
-	github.com/pkg/profile v0.0.0-20170413231811-06b906832ed0
 	github.com/sirupsen/logrus v1.6.0
 	github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372
 	github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1 // indirect
diff --git a/go.sum b/go.sum
index ffd3e483..48f65028 100644
--- a/go.sum
+++ b/go.sum
@@ -20,8 +20,6 @@ github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b h1:8uaXtUkxiy+T/zdLWuxa/PG4so0TPZDZfafFNNSaptE=
 github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
-github.com/pkg/profile v0.0.0-20170413231811-06b906832ed0 h1:wBza4Dlm/NCQF572oSGNZ69flNFxlwIHjtwS6oy3Rvw=
-github.com/pkg/profile v0.0.0-20170413231811-06b906832ed0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
@@ -50,8 +48,12 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSF
 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f h1:3MlESg/jvTr87F4ttA/q4B+uhe/q6qleC9/DP+IwQmY=
 golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200415034506-5d8e1897c761 h1:FVw4lelfGRNPqB3C8qX1m+QyeM2vzToIwlFhEZX42y8=
+golang.org/x/tools v0.0.0-20200415034506-5d8e1897c761/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/pkg/proc/breakpoints.go b/pkg/proc/breakpoints.go
index 3e01bea5..b331dbf0 100644
--- a/pkg/proc/breakpoints.go
+++ b/pkg/proc/breakpoints.go
@@ -237,21 +237,13 @@ func NewBreakpointMap() BreakpointMap {
 	}
 }
 
-// ResetBreakpointIDCounter resets the breakpoint ID counter of bpmap.
-func (bpmap *BreakpointMap) ResetBreakpointIDCounter() {
-	bpmap.breakpointIDCounter = 0
-}
-
-// WriteBreakpointFn is a type that represents a function to be used for
-// writting breakpoings into the target.
-type WriteBreakpointFn func(addr uint64) (file string, line int, fn *Function, originalData []byte, err error)
-
-type clearBreakpointFn func(*Breakpoint) error
-
-// Set creates a breakpoint at addr calling writeBreakpoint. Do not call this
-// function, call proc.Process.SetBreakpoint instead, this function exists
-// to implement proc.Process.SetBreakpoint.
-func (bpmap *BreakpointMap) Set(addr uint64, kind BreakpointKind, cond ast.Expr, writeBreakpoint WriteBreakpointFn) (*Breakpoint, error) {
+// SetBreakpoint sets a breakpoint at addr, and stores it in the process wide
+// break point table.
+func (t *Target) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error) {
+	if valid, err := t.Valid(); !valid {
+		return nil, err
+	}
+	bpmap := t.Breakpoints()
 	if bp, ok := bpmap.M[addr]; ok {
 		// We can overlap one internal breakpoint with one user breakpoint, we
 		// need to support this otherwise a conditional breakpoint can mask a
@@ -268,7 +260,7 @@ func (bpmap *BreakpointMap) Set(addr uint64, kind BreakpointKind, cond ast.Expr,
 		return bp, nil
 	}
 
-	f, l, fn, originalData, err := writeBreakpoint(addr)
+	f, l, fn, originalData, err := t.proc.WriteBreakpoint(addr)
 	if err != nil {
 		return nil, err
 	}
@@ -303,9 +295,10 @@ func (bpmap *BreakpointMap) Set(addr uint64, kind BreakpointKind, cond ast.Expr,
 	return newBreakpoint, nil
 }
 
-// SetWithID creates a breakpoint at addr, with the specified logical ID.
-func (bpmap *BreakpointMap) SetWithID(id int, addr uint64, writeBreakpoint WriteBreakpointFn) (*Breakpoint, error) {
-	bp, err := bpmap.Set(addr, UserBreakpoint, nil, writeBreakpoint)
+// setBreakpointWithID creates a breakpoint at addr, with the specified logical ID.
+func (t *Target) setBreakpointWithID(id int, addr uint64) (*Breakpoint, error) {
+	bpmap := t.Breakpoints()
+	bp, err := t.SetBreakpoint(addr, UserBreakpoint, nil)
 	if err == nil {
 		bp.LogicalID = id
 		bpmap.breakpointIDCounter--
@@ -313,9 +306,12 @@ func (bpmap *BreakpointMap) SetWithID(id int, addr uint64, writeBreakpoint Write
 	return bp, err
 }
 
-// Clear clears the breakpoint at addr.
-// Do not call this function call proc.Process.ClearBreakpoint instead.
-func (bpmap *BreakpointMap) Clear(addr uint64, clearBreakpoint clearBreakpointFn) (*Breakpoint, error) {
+// ClearBreakpoint clears the breakpoint at addr.
+func (t *Target) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
+	if valid, err := t.Valid(); !valid {
+		return nil, err
+	}
+	bpmap := t.Breakpoints()
 	bp, ok := bpmap.M[addr]
 	if !ok {
 		return nil, NoBreakpointError{Addr: addr}
@@ -327,7 +323,7 @@ func (bpmap *BreakpointMap) Clear(addr uint64, clearBreakpoint clearBreakpointFn
 		return bp, nil
 	}
 
-	if err := clearBreakpoint(bp); err != nil {
+	if err := t.proc.EraseBreakpoint(bp); err != nil {
 		return nil, err
 	}
 
@@ -338,9 +334,9 @@ func (bpmap *BreakpointMap) Clear(addr uint64, clearBreakpoint clearBreakpointFn
 
 // ClearInternalBreakpoints removes all internal breakpoints from the map,
 // calling clearBreakpoint on each one.
-// Do not call this function, call proc.Process.ClearInternalBreakpoints
-// instead, this function is used to implement that.
-func (bpmap *BreakpointMap) ClearInternalBreakpoints(clearBreakpoint clearBreakpointFn) error {
+func (t *Target) ClearInternalBreakpoints() error {
+	bpmap := t.Breakpoints()
+	threads := t.ThreadList()
 	for addr, bp := range bpmap.M {
 		bp.Kind = bp.Kind & UserBreakpoint
 		bp.internalCond = nil
@@ -348,9 +344,14 @@ func (bpmap *BreakpointMap) ClearInternalBreakpoints(clearBreakpoint clearBreakp
 		if bp.Kind != 0 {
 			continue
 		}
-		if err := clearBreakpoint(bp); err != nil {
+		if err := t.proc.EraseBreakpoint(bp); err != nil {
 			return err
 		}
+		for _, thread := range threads {
+			if thread.Breakpoint().Breakpoint == bp {
+				thread.Breakpoint().Clear()
+			}
+		}
 		delete(bpmap.M, addr)
 	}
 	return nil
diff --git a/pkg/proc/core/core.go b/pkg/proc/core/core.go
index 41c7df79..984ffdf3 100644
--- a/pkg/proc/core/core.go
+++ b/pkg/proc/core/core.go
@@ -3,7 +3,6 @@ package core
 import (
 	"errors"
 	"fmt"
-	"go/ast"
 	"io"
 
 	"github.com/go-delve/delve/pkg/proc"
@@ -216,7 +215,6 @@ func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, e
 	return proc.NewTarget(p, proc.NewTargetConfig{
 		Path:                exePath,
 		DebugInfoDirs:       debugInfoDirs,
-		WriteBreakpoint:     p.writeBreakpoint,
 		DisableAsyncPreempt: false,
 		StopReason:          proc.StopAttached})
 }
@@ -231,9 +229,9 @@ func (p *process) EntryPoint() (uint64, error) {
 	return p.entryPoint, nil
 }
 
-// writeBreakpoint is a noop function since you
+// WriteBreakpoint is a noop function since you
 // cannot write breakpoints into core files.
-func (p *process) writeBreakpoint(addr uint64) (file string, line int, fn *proc.Function, originalData []byte, err error) {
+func (p *process) WriteBreakpoint(addr uint64) (file string, line int, fn *proc.Function, originalData []byte, err error) {
 	return "", 0, nil, nil, errors.New("cannot write a breakpoint to a core file")
 }
 
@@ -365,10 +363,10 @@ func (p *process) Breakpoints() *proc.BreakpointMap {
 	return &p.breakpoints
 }
 
-// ClearBreakpoint will always return an error as you cannot set or clear
+// EraseBreakpoint will always return an error as you cannot set or clear
 // breakpoints on core files.
-func (p *process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
-	return nil, proc.NoBreakpointError{Addr: addr}
+func (p *process) EraseBreakpoint(bp *proc.Breakpoint) error {
+	return proc.NoBreakpointError{Addr: bp.Addr}
 }
 
 // ClearInternalBreakpoints will always return nil and have no
@@ -430,11 +428,6 @@ func (p *process) Pid() int {
 func (p *process) ResumeNotify(chan<- struct{}) {
 }
 
-// SetBreakpoint will always return an error for core files as you cannot write memory or control execution.
-func (p *process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
-	return nil, ErrWriteCore
-}
-
 // ThreadList will return a list of all threads currently in the process.
 func (p *process) ThreadList() []proc.Thread {
 	r := make([]proc.Thread, 0, len(p.Threads))
diff --git a/pkg/proc/eval.go b/pkg/proc/eval.go
index d541bb87..f43ee5b2 100644
--- a/pkg/proc/eval.go
+++ b/pkg/proc/eval.go
@@ -1214,7 +1214,9 @@ func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) {
 		return nil, xev.Unreadable
 	}
 
-	xev = xev.maybeDereference()
+	if xev.Flags&VariableCPtr == 0 {
+		xev = xev.maybeDereference()
+	}
 
 	idxev, err := scope.evalAST(node.Index)
 	if err != nil {
@@ -1228,11 +1230,13 @@ func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) {
 		if xev == nilVariable {
 			return nil, cantindex
 		}
-		_, isarrptr := xev.RealType.(*godwarf.PtrType).Type.(*godwarf.ArrayType)
-		if !isarrptr {
-			return nil, cantindex
+		if xev.Flags&VariableCPtr == 0 {
+			_, isarrptr := xev.RealType.(*godwarf.PtrType).Type.(*godwarf.ArrayType)
+			if !isarrptr {
+				return nil, cantindex
+			}
+			xev = xev.maybeDereference()
 		}
-		xev = xev.maybeDereference()
 		fallthrough
 
 	case reflect.Slice, reflect.Array, reflect.String:
@@ -1309,6 +1313,11 @@ func (scope *EvalScope) evalReslice(node *ast.SliceExpr) (*Variable, error) {
 			return nil, fmt.Errorf("map index out of bounds")
 		}
 		return xev, nil
+	case reflect.Ptr:
+		if xev.Flags&VariableCPtr != 0 {
+			return xev.reslice(low, high)
+		}
+		fallthrough
 	default:
 		return nil, fmt.Errorf("can not slice \"%s\" (type %s)", exprToString(node.X), xev.TypeString())
 	}
@@ -1844,7 +1853,13 @@ func sameType(t1, t2 godwarf.Type) bool {
 }
 
 func (v *Variable) sliceAccess(idx int) (*Variable, error) {
-	if idx < 0 || int64(idx) >= v.Len {
+	wrong := false
+	if v.Flags&VariableCPtr == 0 {
+		wrong = idx < 0 || int64(idx) >= v.Len
+	} else {
+		wrong = idx < 0
+	}
+	if wrong {
 		return nil, fmt.Errorf("index out of bounds")
 	}
 	mem := v.mem
@@ -1889,7 +1904,18 @@ func (v *Variable) mapAccess(idx *Variable) (*Variable, error) {
 }
 
 func (v *Variable) reslice(low int64, high int64) (*Variable, error) {
-	if low < 0 || low >= v.Len || high < 0 || high > v.Len {
+	wrong := false
+	cptrNeedsFakeSlice := false
+	if v.Flags&VariableCPtr == 0 {
+		wrong = low < 0 || low >= v.Len || high < 0 || high > v.Len
+	} else {
+		wrong = low < 0 || high < 0
+		if high == 0 {
+			high = low
+		}
+		cptrNeedsFakeSlice = v.Kind != reflect.String
+	}
+	if wrong {
 		return nil, fmt.Errorf("index out of bounds")
 	}
 
@@ -1901,7 +1927,7 @@ func (v *Variable) reslice(low int64, high int64) (*Variable, error) {
 	}
 
 	typ := v.DwarfType
-	if _, isarr := v.DwarfType.(*godwarf.ArrayType); isarr {
+	if _, isarr := v.DwarfType.(*godwarf.ArrayType); isarr || cptrNeedsFakeSlice {
 		typ = fakeSliceType(v.fieldType)
 	}
 
diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go
index c88ed334..dbfb82c8 100644
--- a/pkg/proc/gdbserial/gdbserver.go
+++ b/pkg/proc/gdbserial/gdbserver.go
@@ -67,7 +67,6 @@ import (
 	"encoding/binary"
 	"errors"
 	"fmt"
-	"go/ast"
 	"net"
 	"os"
 	"os/exec"
@@ -555,7 +554,6 @@ func (p *gdbProcess) initialize(path string, debugInfoDirs []string, stopReason
 	tgt, err := proc.NewTarget(p, proc.NewTargetConfig{
 		Path:                path,
 		DebugInfoDirs:       debugInfoDirs,
-		WriteBreakpoint:     p.writeBreakpoint,
 		DisableAsyncPreempt: runtime.GOOS == "darwin",
 		StopReason:          stopReason})
 	if err != nil {
@@ -1083,7 +1081,7 @@ func (p *gdbProcess) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
 	return nil, false
 }
 
-func (p *gdbProcess) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
+func (p *gdbProcess) WriteBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
 	f, l, fn := p.bi.PCToLine(uint64(addr))
 
 	if err := p.conn.setBreakpoint(addr); err != nil {
@@ -1093,37 +1091,8 @@ func (p *gdbProcess) writeBreakpoint(addr uint64) (string, int, *proc.Function,
 	return f, l, fn, nil, nil
 }
 
-// SetBreakpoint creates a new breakpoint.
-func (p *gdbProcess) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
-	if p.exited {
-		return nil, &proc.ErrProcessExited{Pid: p.conn.pid}
-	}
-	return p.breakpoints.Set(addr, kind, cond, p.writeBreakpoint)
-}
-
-// ClearBreakpoint clears a breakpoint at the given address.
-func (p *gdbProcess) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
-	if p.exited {
-		return nil, &proc.ErrProcessExited{Pid: p.conn.pid}
-	}
-	return p.breakpoints.Clear(addr, func(bp *proc.Breakpoint) error {
-		return p.conn.clearBreakpoint(bp.Addr)
-	})
-}
-
-// ClearInternalBreakpoints clear all internal use breakpoints like those set by 'next'.
-func (p *gdbProcess) ClearInternalBreakpoints() error {
-	return p.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
-		if err := p.conn.clearBreakpoint(bp.Addr); err != nil {
-			return err
-		}
-		for _, thread := range p.threads {
-			if thread.CurrentBreakpoint.Breakpoint == bp {
-				thread.clearBreakpointState()
-			}
-		}
-		return nil
-	})
+func (p *gdbProcess) EraseBreakpoint(bp *proc.Breakpoint) error {
+	return p.conn.clearBreakpoint(bp.Addr)
 }
 
 type threadUpdater struct {
diff --git a/pkg/proc/interface.go b/pkg/proc/interface.go
index d5f7a729..cd1ad0c8 100644
--- a/pkg/proc/interface.go
+++ b/pkg/proc/interface.go
@@ -1,9 +1,5 @@
 package proc
 
-import (
-	"go/ast"
-)
-
 // Process represents the target of the debugger. This
 // target could be a system process, core file, etc.
 //
@@ -14,8 +10,9 @@ import (
 type Process interface {
 	Info
 	ProcessManipulation
-	BreakpointManipulation
 	RecordingManipulation
+
+	Breakpoints() *BreakpointMap
 }
 
 // ProcessInternal holds a set of methods that are not meant to be called by
@@ -32,6 +29,9 @@ type ProcessInternal interface {
 	Restart(pos string) error
 	Detach(bool) error
 	ContinueOnce() (trapthread Thread, stopReason StopReason, err error)
+
+	WriteBreakpoint(addr uint64) (file string, line int, fn *Function, originalData []byte, err error)
+	EraseBreakpoint(*Breakpoint) error
 }
 
 // RecordingManipulation is an interface for manipulating process recordings.
@@ -101,11 +101,3 @@ type ProcessManipulation interface {
 	// after a call to RequestManualStop.
 	CheckAndClearManualStopRequest() bool
 }
-
-// BreakpointManipulation is an interface for managing breakpoints.
-type BreakpointManipulation interface {
-	Breakpoints() *BreakpointMap
-	SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error)
-	ClearBreakpoint(addr uint64) (*Breakpoint, error)
-	ClearInternalBreakpoints() error
-}
diff --git a/pkg/proc/native/proc.go b/pkg/proc/native/proc.go
index 5381c506..9e4aeb61 100644
--- a/pkg/proc/native/proc.go
+++ b/pkg/proc/native/proc.go
@@ -1,7 +1,6 @@
 package native
 
 import (
-	"go/ast"
 	"os"
 	"runtime"
 	"sync"
@@ -115,15 +114,6 @@ func (dbp *nativeProcess) Detach(kill bool) (err error) {
 		dbp.bi.Close()
 		return nil
 	}
-	// Clean up any breakpoints we've set.
-	for _, bp := range dbp.breakpoints.M {
-		if bp != nil {
-			_, err := dbp.ClearBreakpoint(bp.Addr)
-			if err != nil {
-				return err
-			}
-		}
-	}
 	dbp.execPtraceFunc(func() {
 		err = dbp.detach(kill)
 		if err != nil {
@@ -215,7 +205,7 @@ func (dbp *nativeProcess) CheckAndClearManualStopRequest() bool {
 	return msr
 }
 
-func (dbp *nativeProcess) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
+func (dbp *nativeProcess) WriteBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
 	f, l, fn := dbp.bi.PCToLine(uint64(addr))
 
 	originalData := make([]byte, dbp.bi.Arch.BreakpointSize())
@@ -230,18 +220,8 @@ func (dbp *nativeProcess) writeBreakpoint(addr uint64) (string, int, *proc.Funct
 	return f, l, fn, originalData, nil
 }
 
-// SetBreakpoint sets a breakpoint at addr, and stores it in the process wide
-// break point table.
-func (dbp *nativeProcess) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
-	return dbp.breakpoints.Set(addr, kind, cond, dbp.writeBreakpoint)
-}
-
-// ClearBreakpoint clears the breakpoint at addr.
-func (dbp *nativeProcess) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
-	if dbp.exited {
-		return nil, &proc.ErrProcessExited{Pid: dbp.Pid()}
-	}
-	return dbp.breakpoints.Clear(addr, dbp.currentThread.ClearBreakpoint)
+func (dbp *nativeProcess) EraseBreakpoint(bp *proc.Breakpoint) error {
+	return dbp.currentThread.ClearBreakpoint(bp)
 }
 
 // ContinueOnce will continue the target until it stops.
@@ -305,27 +285,10 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
 	return proc.NewTarget(dbp, proc.NewTargetConfig{
 		Path:                path,
 		DebugInfoDirs:       debugInfoDirs,
-		WriteBreakpoint:     dbp.writeBreakpoint,
 		DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd",
 		StopReason:          stopReason})
 }
 
-// ClearInternalBreakpoints will clear all non-user set breakpoints. These
-// breakpoints are set for internal operations such as 'next'.
-func (dbp *nativeProcess) ClearInternalBreakpoints() error {
-	return dbp.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
-		if err := dbp.currentThread.ClearBreakpoint(bp); err != nil {
-			return err
-		}
-		for _, thread := range dbp.threads {
-			if thread.CurrentBreakpoint.Breakpoint == bp {
-				thread.CurrentBreakpoint.Clear()
-			}
-		}
-		return nil
-	})
-}
-
 func (dbp *nativeProcess) 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
diff --git a/pkg/proc/target.go b/pkg/proc/target.go
index 5aedcf5e..9711275e 100644
--- a/pkg/proc/target.go
+++ b/pkg/proc/target.go
@@ -80,11 +80,10 @@ const (
 
 // NewTargetConfig contains the configuration for a new Target object,
 type NewTargetConfig struct {
-	Path                string            // path of the main executable
-	DebugInfoDirs       []string          // Directories to search for split debug info
-	WriteBreakpoint     WriteBreakpointFn // Function to write a breakpoint to the target process
-	DisableAsyncPreempt bool              // Go 1.14 asynchronous preemption should be disabled
-	StopReason          StopReason        // Initial stop reason
+	Path                string     // path of the main executable
+	DebugInfoDirs       []string   // Directories to search for split debug info
+	DisableAsyncPreempt bool       // Go 1.14 asynchronous preemption should be disabled
+	StopReason          StopReason // Initial stop reason
 }
 
 // DisableAsyncPreemptEnv returns a process environment (like os.Environ)
@@ -128,8 +127,8 @@ func NewTarget(p Process, cfg NewTargetConfig) (*Target, error) {
 	g, _ := GetG(p.CurrentThread())
 	t.selectedGoroutine = g
 
-	createUnrecoveredPanicBreakpoint(p, cfg.WriteBreakpoint)
-	createFatalThrowBreakpoint(p, cfg.WriteBreakpoint)
+	t.createUnrecoveredPanicBreakpoint()
+	t.createFatalThrowBreakpoint()
 
 	t.gcache.init(p.BinInfo())
 
@@ -216,8 +215,18 @@ func (p *Target) SwitchThread(tid int) error {
 // we were previously debugging.
 // If kill is true then the process will be killed when we detach.
 func (t *Target) Detach(kill bool) error {
-	if !kill && t.asyncPreemptChanged {
-		setAsyncPreemptOff(t, t.asyncPreemptOff)
+	if !kill {
+		if t.asyncPreemptChanged {
+			setAsyncPreemptOff(t, t.asyncPreemptOff)
+		}
+		for _, bp := range t.Breakpoints().M {
+			if bp != nil {
+				_, err := t.ClearBreakpoint(bp.Addr)
+				if err != nil {
+					return err
+				}
+			}
+		}
 	}
 	t.StopReason = StopUnknown
 	return t.proc.Detach(kill)
@@ -255,13 +264,13 @@ func setAsyncPreemptOff(p *Target, v int64) {
 }
 
 // createUnrecoveredPanicBreakpoint creates the unrecoverable-panic breakpoint.
-func createUnrecoveredPanicBreakpoint(p Process, writeBreakpoint WriteBreakpointFn) {
-	panicpcs, err := FindFunctionLocation(p, "runtime.startpanic", 0)
+func (t *Target) createUnrecoveredPanicBreakpoint() {
+	panicpcs, err := FindFunctionLocation(t.Process, "runtime.startpanic", 0)
 	if _, isFnNotFound := err.(*ErrFunctionNotFound); isFnNotFound {
-		panicpcs, err = FindFunctionLocation(p, "runtime.fatalpanic", 0)
+		panicpcs, err = FindFunctionLocation(t.Process, "runtime.fatalpanic", 0)
 	}
 	if err == nil {
-		bp, err := p.Breakpoints().SetWithID(unrecoveredPanicID, panicpcs[0], writeBreakpoint)
+		bp, err := t.setBreakpointWithID(unrecoveredPanicID, panicpcs[0])
 		if err == nil {
 			bp.Name = UnrecoveredPanic
 			bp.Variables = []string{"runtime.curg._panic.arg"}
@@ -270,10 +279,10 @@ func createUnrecoveredPanicBreakpoint(p Process, writeBreakpoint WriteBreakpoint
 }
 
 // createFatalThrowBreakpoint creates the a breakpoint as runtime.fatalthrow.
-func createFatalThrowBreakpoint(p Process, writeBreakpoint WriteBreakpointFn) {
-	fatalpcs, err := FindFunctionLocation(p, "runtime.fatalthrow", 0)
+func (t *Target) createFatalThrowBreakpoint() {
+	fatalpcs, err := FindFunctionLocation(t.Process, "runtime.fatalthrow", 0)
 	if err == nil {
-		bp, err := p.Breakpoints().SetWithID(fatalThrowID, fatalpcs[0], writeBreakpoint)
+		bp, err := t.setBreakpointWithID(fatalThrowID, fatalpcs[0])
 		if err == nil {
 			bp.Name = FatalThrow
 		}
diff --git a/pkg/proc/target_exec.go b/pkg/proc/target_exec.go
index 792a66ca..9527ddd9 100644
--- a/pkg/proc/target_exec.go
+++ b/pkg/proc/target_exec.go
@@ -7,6 +7,7 @@ import (
 	"go/ast"
 	"go/token"
 	"path/filepath"
+	"strings"
 
 	"github.com/go-delve/delve/pkg/astutil"
 	"github.com/go-delve/delve/pkg/dwarf/reader"
@@ -146,10 +147,17 @@ func (dbp *Target) Continue() error {
 				}
 				if dbp.GetDirection() == Forward {
 					text, err := disassembleCurrentInstruction(dbp, curthread)
+					if err != nil {
+						return err
+					}
+					var fn *Function
+					if loc, _ := curthread.Location(); loc != nil {
+						fn = loc.Fn
+					}
 					// 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 = setStepIntoBreakpoint(dbp, text, sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil {
+					if err = setStepIntoBreakpoint(dbp, fn, text, sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil {
 						return err
 					}
 				} else {
@@ -513,7 +521,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
 	sameFrameCond := astutil.And(sameGCond, frameoffCondition(&topframe))
 
 	if stepInto && !backward {
-		err := setStepIntoBreakpoints(dbp, text, topframe, sameGCond)
+		err := setStepIntoBreakpoints(dbp, topframe.Current.Fn, text, topframe, sameGCond)
 		if err != nil {
 			return err
 		}
@@ -625,14 +633,14 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
 	return nil
 }
 
-func setStepIntoBreakpoints(dbp Process, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
+func setStepIntoBreakpoints(dbp *Target, curfn *Function, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
 	for _, instr := range text {
 		if instr.Loc.File != topframe.Current.File || instr.Loc.Line != topframe.Current.Line || !instr.IsCall() {
 			continue
 		}
 
 		if instr.DestLoc != nil {
-			if err := setStepIntoBreakpoint(dbp, []AsmInstruction{instr}, sameGCond); err != nil {
+			if err := setStepIntoBreakpoint(dbp, curfn, []AsmInstruction{instr}, sameGCond); err != nil {
 				return err
 			}
 		} else {
@@ -645,7 +653,7 @@ func setStepIntoBreakpoints(dbp Process, text []AsmInstruction, topframe Stackfr
 	return nil
 }
 
-func setStepIntoBreakpointsReverse(dbp Process, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
+func setStepIntoBreakpointsReverse(dbp *Target, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
 	// Set a breakpoint after every CALL instruction
 	for i, instr := range text {
 		if instr.Loc.File != topframe.Current.File || !instr.IsCall() || instr.DestLoc == nil || instr.DestLoc.Fn == nil {
@@ -708,11 +716,16 @@ func removePCsBetween(pcs []uint64, start, end uint64) []uint64 {
 	return out
 }
 
-func setStepIntoBreakpoint(dbp Process, text []AsmInstruction, cond ast.Expr) error {
+func setStepIntoBreakpoint(dbp *Target, curfn *Function, text []AsmInstruction, cond ast.Expr) error {
 	if len(text) <= 0 {
 		return nil
 	}
 
+	// If the current function is already a runtime function then
+	// setStepIntoBreakpoint is allowed to step into unexported runtime
+	// functions.
+	stepIntoUnexportedRuntime := curfn != nil && strings.HasPrefix(curfn.Name, "runtime.")
+
 	instr := text[0]
 
 	if instr.DestLoc == nil {
@@ -724,7 +737,7 @@ func setStepIntoBreakpoint(dbp Process, text []AsmInstruction, cond ast.Expr) er
 	fn := instr.DestLoc.Fn
 
 	// Skip unexported runtime functions
-	if fn != nil && fn.privateRuntime() {
+	if !stepIntoUnexportedRuntime && fn != nil && fn.privateRuntime() {
 		return nil
 	}
 
@@ -873,7 +886,7 @@ func skipAutogeneratedWrappersOut(g *G, thread Thread, startTopframe, startRetfr
 
 // setDeferBreakpoint is a helper function used by next and StepOut to set a
 // breakpoint on the first deferred function.
-func setDeferBreakpoint(p Process, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr, stepInto bool) (uint64, error) {
+func setDeferBreakpoint(p *Target, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr, stepInto bool) (uint64, error) {
 	// Set breakpoint on the most recently deferred function (if any)
 	var deferpc uint64
 	if topframe.TopmostDefer != nil && topframe.TopmostDefer.DeferredPC != 0 {
diff --git a/pkg/proc/variables.go b/pkg/proc/variables.go
index 51a695bf..97b8157f 100644
--- a/pkg/proc/variables.go
+++ b/pkg/proc/variables.go
@@ -75,6 +75,8 @@ const (
 	// the variable is the return value of a function call and allocated on a
 	// frame that no longer exists)
 	VariableFakeAddress
+	// VariableCPrt means the variable is a C pointer
+	VariableCPtr
 )
 
 // Variable represents a variable. It contains the address, name,
@@ -612,6 +614,18 @@ func newVariable(name string, addr uintptr, dwarfType godwarf.Type, bi *BinaryIn
 		v.Kind = reflect.Ptr
 		if _, isvoid := t.Type.(*godwarf.VoidType); isvoid {
 			v.Kind = reflect.UnsafePointer
+		} else if isCgoType(bi, t) {
+			v.Flags |= VariableCPtr
+			v.fieldType = t.Type
+			v.stride = alignAddr(v.fieldType.Size(), v.fieldType.Align())
+			v.Len = 0
+			if isCgoCharPtr(bi, t) {
+				v.Kind = reflect.String
+			}
+			if v.Addr != 0 {
+				n, err := readUintRaw(v.mem, v.Addr, int64(v.bi.Arch.PtrSize()))
+				v.Base, v.Unreadable = uintptr(n), err
+			}
 		}
 	case *godwarf.ChanType:
 		v.Kind = reflect.Chan
@@ -656,6 +670,14 @@ func newVariable(name string, addr uintptr, dwarfType godwarf.Type, bi *BinaryIn
 		}
 	case *godwarf.IntType:
 		v.Kind = reflect.Int
+	case *godwarf.CharType:
+		// Rest of the code assumes that Kind == reflect.Int implies RealType ==
+		// godwarf.IntType.
+		v.RealType = &godwarf.IntType{BasicType: t.BasicType}
+		v.Kind = reflect.Int
+	case *godwarf.UcharType:
+		v.RealType = &godwarf.IntType{BasicType: t.BasicType}
+		v.Kind = reflect.Int
 	case *godwarf.UintType:
 		v.Kind = reflect.Uint
 	case *godwarf.FloatType:
@@ -1204,7 +1226,18 @@ func (v *Variable) loadValueInternal(recurseLevel int, cfg LoadConfig) {
 
 	case reflect.String:
 		var val string
-		val, v.Unreadable = readStringValue(DereferenceMemory(v.mem), v.Base, v.Len, cfg)
+		if v.Flags&VariableCPtr == 0 {
+			val, v.Unreadable = readStringValue(DereferenceMemory(v.mem), v.Base, v.Len, cfg)
+		} else {
+			var done bool
+			val, done, v.Unreadable = readCStringValue(DereferenceMemory(v.mem), v.Base, cfg)
+			if v.Unreadable == nil {
+				v.Len = int64(len(val))
+				if !done {
+					v.Len++
+				}
+			}
+		}
 		v.Value = constant.MakeString(val)
 
 	case reflect.Slice, reflect.Array:
@@ -1341,9 +1374,50 @@ func readStringValue(mem MemoryReadWriter, addr uintptr, strlen int64, cfg LoadC
 		return "", fmt.Errorf("could not read string at %#v due to %s", addr, err)
 	}
 
-	retstr := *(*string)(unsafe.Pointer(&val))
+	return string(val), nil
+}
+
+func readCStringValue(mem MemoryReadWriter, addr uintptr, cfg LoadConfig) (string, bool, error) {
+	buf := make([]byte, cfg.MaxStringLen) //
+	val := buf[:0]                        // part of the string we've already read
+
+	for len(buf) > 0 {
+		// Reads some memory for the string but (a) never more than we would
+		// need (considering cfg.MaxStringLen), and (b) never cross a page boundary
+		// until we're sure we have to.
+		// The page check is needed to avoid getting an I/O error for reading
+		// memory we don't even need.
+		// We don't know how big a page is but 1024 is a reasonable minimum common
+		// divisor for all architectures.
+		curaddr := addr + uintptr(len(val))
+		maxsize := int(alignAddr(int64(curaddr+1), 1024) - int64(curaddr))
+		size := len(buf)
+		if size > maxsize {
+			size = maxsize
+		}
+
+		_, err := mem.ReadMemory(buf[:size], curaddr)
+		if err != nil {
+			return "", false, fmt.Errorf("could not read string at %#v due to %s", addr, err)
+		}
+
+		done := false
+		for i := 0; i < size; i++ {
+			if buf[i] == 0 {
+				done = true
+				size = i
+				break
+			}
+		}
+
+		val = val[:len(val)+size]
+		buf = buf[size:]
+		if done {
+			return string(val), true, nil
+		}
+	}
 
-	return retstr, nil
+	return string(val), false, nil
 }
 
 const (
@@ -2157,6 +2231,37 @@ func popcnt(x uint64) int {
 	return int(x) & (1<<7 - 1)
 }
 
+func isCgoType(bi *BinaryInfo, typ godwarf.Type) bool {
+	cu := bi.Images[typ.Common().Index].findCompileUnitForOffset(typ.Common().Offset)
+	if cu == nil {
+		return false
+	}
+	return !cu.isgo
+}
+
+func isCgoCharPtr(bi *BinaryInfo, typ *godwarf.PtrType) bool {
+	if !isCgoType(bi, typ) {
+		return false
+	}
+
+	fieldtyp := typ.Type
+resolveQualTypedef:
+	for {
+		switch t := fieldtyp.(type) {
+		case *godwarf.QualType:
+			fieldtyp = t.Type
+		case *godwarf.TypedefType:
+			fieldtyp = t.Type
+		default:
+			break resolveQualTypedef
+		}
+	}
+
+	_, ischar := fieldtyp.(*godwarf.CharType)
+	_, isuchar := fieldtyp.(*godwarf.UcharType)
+	return ischar || isuchar
+}
+
 func (cm constantsMap) Get(typ godwarf.Type) *constantType {
 	ctyp := cm[dwarfRef{typ.Common().Index, typ.Common().Offset}]
 	if ctyp == nil {
diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go
index 419ebbbb..9ec2bf00 100644
--- a/pkg/terminal/command.go
+++ b/pkg/terminal/command.go
@@ -143,6 +143,7 @@ For live targets the command takes the following forms:
 If newargv is omitted the process is restarted (or re-recorded) with the same argument vector.
 If -noargs is specified instead, the argument vector is cleared.
 `},
+		{aliases: []string{"rebuild"}, group: runCmds, cmdFn: c.rebuild, allowedPrefixes: revPrefix, helpMsg: "Rebuild the target executable and restarts it. It does not work if the executable was not built by delve."},
 		{aliases: []string{"continue", "c"}, group: runCmds, cmdFn: c.cont, allowedPrefixes: revPrefix, helpMsg: "Run until breakpoint or program termination."},
 		{aliases: []string{"step", "s"}, group: runCmds, cmdFn: c.step, allowedPrefixes: revPrefix, helpMsg: "Single step through program."},
 		{aliases: []string{"step-instruction", "si"}, group: runCmds, allowedPrefixes: revPrefix, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
@@ -1028,7 +1029,7 @@ func restartLive(t *Term, ctx callContext, args string) error {
 }
 
 func restartIntl(t *Term, rerecord bool, restartPos string, resetArgs bool, newArgv []string) error {
-	discarded, err := t.client.RestartFrom(rerecord, restartPos, resetArgs, newArgv)
+	discarded, err := t.client.RestartFrom(rerecord, restartPos, resetArgs, newArgv, false)
 	if err != nil {
 		return err
 	}
@@ -1073,6 +1074,18 @@ func printcontextNoState(t *Term) {
 	printcontext(t, state)
 }
 
+func (c *Commands) rebuild(t *Term, ctx callContext, args string) error {
+	if ctx.Prefix == revPrefix {
+		return c.rewind(t, ctx, args)
+	}
+	defer t.onStop()
+	discarded, err := t.client.Restart(true)
+	if len(discarded) > 0 {
+		fmt.Printf("not all breakpoints could be restored.")
+	}
+	return err
+}
+
 func (c *Commands) cont(t *Term, ctx callContext, args string) error {
 	if ctx.Prefix == revPrefix {
 		return c.rewind(t, ctx, args)
@@ -2269,7 +2282,7 @@ func printTracepoint(th *api.Thread, bpname string, fn *api.Function, args strin
 		fmt.Fprintf(os.Stderr, " => (%s)\n", strings.Join(retVals, ","))
 	}
 	if th.Breakpoint.TraceReturn || !hasReturnValue {
-		if th.BreakpointInfo.Stacktrace != nil {
+		if th.BreakpointInfo != nil && th.BreakpointInfo.Stacktrace != nil {
 			fmt.Fprintf(os.Stderr, "\tStack:\n")
 			printStack(os.Stderr, th.BreakpointInfo.Stacktrace, "\t\t", false)
 		}
diff --git a/pkg/terminal/starbind/starlark_mapping.go b/pkg/terminal/starbind/starlark_mapping.go
index 5374d88d..1480507e 100644
--- a/pkg/terminal/starbind/starlark_mapping.go
+++ b/pkg/terminal/starbind/starlark_mapping.go
@@ -1091,6 +1091,12 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
 				return starlark.None, decorateError(thread, err)
 			}
 		}
+		if len(args) > 4 && args[4] != starlark.None {
+			err := unmarshalStarlarkValue(args[4], &rpcArgs.Rebuild, "Rebuild")
+			if err != nil {
+				return starlark.None, decorateError(thread, err)
+			}
+		}
 		for _, kv := range kwargs {
 			var err error
 			switch kv[0].(starlark.String) {
@@ -1102,6 +1108,8 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
 				err = unmarshalStarlarkValue(kv[1], &rpcArgs.NewArgs, "NewArgs")
 			case "Rerecord":
 				err = unmarshalStarlarkValue(kv[1], &rpcArgs.Rerecord, "Rerecord")
+			case "Rebuild":
+				err = unmarshalStarlarkValue(kv[1], &rpcArgs.Rebuild, "Rebuild")
 			default:
 				err = fmt.Errorf("unknown argument %q", kv[0])
 			}
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 67422e6f..bda60614 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -14,7 +14,7 @@ type Version struct {
 var (
 	// DelveVersion is the current version of Delve.
 	DelveVersion = Version{
-		Major: "1", Minor: "4", Patch: "0", Metadata: "",
+		Major: "1", Minor: "4", Patch: "1", Metadata: "",
 		Build: "$Id$",
 	}
 )
diff --git a/service/api/conversions.go b/service/api/conversions.go
index 321b7a4e..c22035e1 100644
--- a/service/api/conversions.go
+++ b/service/api/conversions.go
@@ -257,7 +257,10 @@ func ConvertGoroutine(g *proc.G) *Goroutine {
 	if th != nil {
 		tid = th.ThreadID()
 	}
-	r := &Goroutine{
+	if g.Unreadable != nil {
+		return &Goroutine{Unreadable: g.Unreadable.Error()}
+	}
+	return &Goroutine{
 		ID:             g.ID,
 		CurrentLoc:     ConvertLocation(g.CurrentLoc),
 		UserCurrentLoc: ConvertLocation(g.UserCurrent()),
@@ -266,10 +269,6 @@ func ConvertGoroutine(g *proc.G) *Goroutine {
 		ThreadID:       tid,
 		Labels:         g.Labels(),
 	}
-	if g.Unreadable != nil {
-		r.Unreadable = g.Unreadable.Error()
-	}
-	return r
 }
 
 // ConvertLocation converts from proc.Location to api.Location.
diff --git a/service/client.go b/service/client.go
index ed5b8f98..03efb276 100644
--- a/service/client.go
+++ b/service/client.go
@@ -18,10 +18,10 @@ type Client interface {
 	// Detach detaches the debugger, optionally killing the process.
 	Detach(killProcess bool) error
 
-	// Restarts program.
-	Restart() ([]api.DiscardedBreakpoint, error)
+	// Restarts program. Set true if you want to rebuild the process we are debugging.
+	Restart(rebuild bool) ([]api.DiscardedBreakpoint, error)
 	// Restarts program from the specified position.
-	RestartFrom(rerecord bool, pos string, resetArgs bool, newArgs []string) ([]api.DiscardedBreakpoint, error)
+	RestartFrom(rerecord bool, pos string, resetArgs bool, newArgs []string, rebuild bool) ([]api.DiscardedBreakpoint, error)
 
 	// GetState returns the current debugger state.
 	GetState() (*api.DebuggerState, error)
diff --git a/service/dap/server.go b/service/dap/server.go
index eb140818..c2fd0f20 100644
--- a/service/dap/server.go
+++ b/service/dap/server.go
@@ -402,9 +402,16 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
 			return
 		}
 
-		buildFlags, ok := request.Arguments["buildFlags"].(string)
-		if !ok {
-			buildFlags = ""
+		buildFlags := ""
+		buildFlagsArg, ok := request.Arguments["buildFlags"]
+		if ok {
+			buildFlags, ok = buildFlagsArg.(string)
+			if !ok {
+				s.sendErrorResponse(request.Request,
+					FailedToContinue, "Failed to launch",
+					fmt.Sprintf("'buildFlags' attribute '%v' in debug configuration is not a string.", buildFlagsArg))
+				return
+			}
 		}
 
 		switch mode {
diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go
index 2bdcb8ca..7a567f3f 100644
--- a/service/debugger/debugger.go
+++ b/service/debugger/debugger.go
@@ -16,6 +16,7 @@ import (
 	"time"
 
 	"github.com/go-delve/delve/pkg/dwarf/op"
+	"github.com/go-delve/delve/pkg/gobuild"
 	"github.com/go-delve/delve/pkg/goversion"
 	"github.com/go-delve/delve/pkg/locspec"
 	"github.com/go-delve/delve/pkg/logflags"
@@ -63,6 +64,15 @@ type Debugger struct {
 	recordMutex   sync.Mutex
 }
 
+type ExecuteKind int
+
+const (
+	ExecutingExistingFile = ExecuteKind(iota)
+	ExecutingGeneratedFile
+	ExecutingGeneratedTest
+	ExecutingOther
+)
+
 // Config provides the configuration to start a Debugger.
 //
 // Only one of ProcessArgs or AttachPid should be specified. If ProcessArgs is
@@ -98,6 +108,15 @@ type Config struct {
 	// TTY is passed along to the target process on creation. Used to specify a
 	// TTY for that process.
 	TTY string
+
+	// Packages contains the packages that we are debugging.
+	Packages []string
+
+	// BuildFlags contains the flags passed to the compiler.
+	BuildFlags string
+
+	// ExecuteKind contains the kind of the executed program.
+	ExecuteKind ExecuteKind
 }
 
 // New creates a new Debugger. ProcessArgs specify the commandline arguments for the
@@ -390,7 +409,7 @@ func (d *Debugger) detach(kill bool) error {
 // If the target process is a recording it will restart it from the given
 // position. If pos starts with 'c' it's a checkpoint ID, otherwise it's an
 // event number. If resetArgs is true, newArgs will replace the process args.
-func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []string) ([]api.DiscardedBreakpoint, error) {
+func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []string, rebuild bool) ([]api.DiscardedBreakpoint, error) {
 	d.targetMutex.Lock()
 	defer d.targetMutex.Unlock()
 
@@ -421,6 +440,25 @@ func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []
 	}
 	var p *proc.Target
 	var err error
+
+	if rebuild {
+		switch d.config.ExecuteKind {
+		case ExecutingGeneratedFile:
+			err = gobuild.GoBuild(d.processArgs[0], d.config.Packages, d.config.BuildFlags)
+			if err != nil {
+				return nil, fmt.Errorf("could not rebuild process: %s", err)
+			}
+		case ExecutingGeneratedTest:
+			err = gobuild.GoTestBuild(d.processArgs[0], d.config.Packages, d.config.BuildFlags)
+			if err != nil {
+				return nil, fmt.Errorf("could not rebuild process: %s", err)
+			}
+		default:
+			// We cannot build a process that we didn't start, because we don't know how it was built.
+			return nil, fmt.Errorf("cannot rebuild a binary")
+		}
+	}
+
 	if recorded {
 		run, stop, err2 := gdbserial.RecordAsync(d.processArgs, d.config.WorkingDir, false)
 		if err2 != nil {
@@ -450,6 +488,10 @@ func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []
 			}
 			createLogicalBreakpoint(p, addrs, oldBp)
 		} else {
+			// Avoid setting a breakpoint based on address when rebuilding
+			if rebuild {
+				continue
+			}
 			newBp, err := p.SetBreakpoint(oldBp.Addr, proc.UserBreakpoint, nil)
 			if err != nil {
 				return nil, err
@@ -581,7 +623,7 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin
 
 // createLogicalBreakpoint creates one physical breakpoint for each address
 // in addrs and associates all of them with the same logical breakpoint.
-func createLogicalBreakpoint(p proc.Process, addrs []uint64, requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
+func createLogicalBreakpoint(p *proc.Target, addrs []uint64, requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
 	bps := make([]*proc.Breakpoint, len(addrs))
 	var err error
 	for i := range addrs {
diff --git a/service/rpc1/server.go b/service/rpc1/server.go
index 7d6f4f2f..d798307d 100644
--- a/service/rpc1/server.go
+++ b/service/rpc1/server.go
@@ -46,7 +46,7 @@ func (s *RPCServer) Restart(arg1 interface{}, arg2 *int) error {
 	if s.config.Debugger.AttachPid != 0 {
 		return errors.New("cannot restart process Delve did not create")
 	}
-	_, err := s.debugger.Restart(false, "", false, nil)
+	_, err := s.debugger.Restart(false, "", false, nil, false)
 	return err
 }
 
diff --git a/service/rpc2/client.go b/service/rpc2/client.go
index 0366b1c1..c738df26 100644
--- a/service/rpc2/client.go
+++ b/service/rpc2/client.go
@@ -60,15 +60,15 @@ func (c *RPCClient) Detach(kill bool) error {
 	return c.call("Detach", DetachIn{kill}, out)
 }
 
-func (c *RPCClient) Restart() ([]api.DiscardedBreakpoint, error) {
+func (c *RPCClient) Restart(rebuild bool) ([]api.DiscardedBreakpoint, error) {
 	out := new(RestartOut)
-	err := c.call("Restart", RestartIn{"", false, nil, false}, out)
+	err := c.call("Restart", RestartIn{"", false, nil, false, rebuild}, out)
 	return out.DiscardedBreakpoints, err
 }
 
-func (c *RPCClient) RestartFrom(rerecord bool, pos string, resetArgs bool, newArgs []string) ([]api.DiscardedBreakpoint, error) {
+func (c *RPCClient) RestartFrom(rerecord bool, pos string, resetArgs bool, newArgs []string, rebuild bool) ([]api.DiscardedBreakpoint, error) {
 	out := new(RestartOut)
-	err := c.call("Restart", RestartIn{pos, resetArgs, newArgs, rerecord}, out)
+	err := c.call("Restart", RestartIn{pos, resetArgs, newArgs, rerecord, rebuild}, out)
 	return out.DiscardedBreakpoints, err
 }
 
diff --git a/service/rpc2/server.go b/service/rpc2/server.go
index b9a1ad58..4d55fb17 100644
--- a/service/rpc2/server.go
+++ b/service/rpc2/server.go
@@ -76,6 +76,9 @@ type RestartIn struct {
 
 	// When Rerecord is set the target will be rerecorded
 	Rerecord bool
+
+	// When Rebuild is set the process will be build again
+	Rebuild bool
 }
 
 type RestartOut struct {
@@ -90,7 +93,7 @@ func (s *RPCServer) Restart(arg RestartIn, cb service.RPCCallback) {
 	}
 	var out RestartOut
 	var err error
-	out.DiscardedBreakpoints, err = s.debugger.Restart(arg.Rerecord, arg.Position, arg.ResetArgs, arg.NewArgs)
+	out.DiscardedBreakpoints, err = s.debugger.Restart(arg.Rerecord, arg.Position, arg.ResetArgs, arg.NewArgs, arg.Rebuild)
 	cb.Return(out, err)
 }
 
diff --git a/vendor/github.com/pkg/profile/.travis.yml b/vendor/github.com/pkg/profile/.travis.yml
deleted file mode 100644
index 192c5c27..00000000
--- a/vendor/github.com/pkg/profile/.travis.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-language: go
-go_import_path: github.com/pkg/profile
-go:
-  - 1.4.3
-  - 1.5.2
-  - 1.6.3
-  - tip
-
-script:
-  - go test github.com/pkg/profile
-  - go test -race github.com/pkg/profile
diff --git a/vendor/github.com/pkg/profile/AUTHORS b/vendor/github.com/pkg/profile/AUTHORS
deleted file mode 100644
index 00441d35..00000000
--- a/vendor/github.com/pkg/profile/AUTHORS
+++ /dev/null
@@ -1,1 +0,0 @@
-Dave Cheney <dave@cheney.net>
diff --git a/vendor/github.com/pkg/profile/LICENSE b/vendor/github.com/pkg/profile/LICENSE
deleted file mode 100644
index f747a841..00000000
--- a/vendor/github.com/pkg/profile/LICENSE
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2013 Dave Cheney. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-   * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-   * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/pkg/profile/README.md b/vendor/github.com/pkg/profile/README.md
deleted file mode 100644
index 37bfa58c..00000000
--- a/vendor/github.com/pkg/profile/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-profile
-=======
-
-Simple profiling support package for Go
-
-[![Build Status](https://travis-ci.org/pkg/profile.svg?branch=master)](https://travis-ci.org/pkg/profile) [![GoDoc](http://godoc.org/github.com/pkg/profile?status.svg)](http://godoc.org/github.com/pkg/profile)
-
-
-installation
-------------
-
-    go get github.com/pkg/profile
-
-usage
------
-
-Enabling profiling in your application is as simple as one line at the top of your main function
-
-```go
-import "github.com/pkg/profile"
-
-func main() {
-    defer profile.Start().Stop()
-    ...
-}
-```
-
-options
--------
-
-What to profile is controlled by config value passed to profile.Start. 
-By default CPU profiling is enabled.
-
-```go
-import "github.com/pkg/profile"
-
-func main() {
-    // p.Stop() must be called before the program exits to
-    // ensure profiling information is written to disk.
-    p := profile.Start(profile.MemProfile, profile.ProfilePath("."), profile.NoShutdownHook)
-    ...
-}
-```
-
-Several convenience package level values are provided for cpu, memory, and block (contention) profiling.
-
-For more complex options, consult the [documentation](http://godoc.org/github.com/pkg/profile).
-
-contributing
-------------
-
-We welcome pull requests, bug fixes and issue reports.
-
-Before proposing a change, please discuss it first by raising an issue.
diff --git a/vendor/github.com/pkg/profile/mutex.go b/vendor/github.com/pkg/profile/mutex.go
deleted file mode 100644
index e69c5b44..00000000
--- a/vendor/github.com/pkg/profile/mutex.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build go1.8
-
-package profile
-
-import "runtime"
-
-func enableMutexProfile() {
-	runtime.SetMutexProfileFraction(1)
-}
-
-func disableMutexProfile() {
-	runtime.SetMutexProfileFraction(0)
-}
diff --git a/vendor/github.com/pkg/profile/mutex17.go b/vendor/github.com/pkg/profile/mutex17.go
deleted file mode 100644
index b004c21d..00000000
--- a/vendor/github.com/pkg/profile/mutex17.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build !go1.8
-
-package profile
-
-// mock mutex support for Go 1.7 and earlier.
-
-func enableMutexProfile() {}
-
-func disableMutexProfile() {}
diff --git a/vendor/github.com/pkg/profile/profile.go b/vendor/github.com/pkg/profile/profile.go
deleted file mode 100644
index c44913a4..00000000
--- a/vendor/github.com/pkg/profile/profile.go
+++ /dev/null
@@ -1,244 +0,0 @@
-// Package profile provides a simple way to manage runtime/pprof
-// profiling of your Go application.
-package profile
-
-import (
-	"io/ioutil"
-	"log"
-	"os"
-	"os/signal"
-	"path/filepath"
-	"runtime"
-	"runtime/pprof"
-	"sync/atomic"
-)
-
-const (
-	cpuMode = iota
-	memMode
-	mutexMode
-	blockMode
-	traceMode
-)
-
-// Profile represents an active profiling session.
-type Profile struct {
-	// quiet suppresses informational messages during profiling.
-	quiet bool
-
-	// noShutdownHook controls whether the profiling package should
-	// hook SIGINT to write profiles cleanly.
-	noShutdownHook bool
-
-	// mode holds the type of profiling that will be made
-	mode int
-
-	// path holds the base path where various profiling files are  written.
-	// If blank, the base path will be generated by ioutil.TempDir.
-	path string
-
-	// memProfileRate holds the rate for the memory profile.
-	memProfileRate int
-
-	// closer holds a cleanup function that run after each profile
-	closer func()
-
-	// stopped records if a call to profile.Stop has been made
-	stopped uint32
-}
-
-// NoShutdownHook controls whether the profiling package should
-// hook SIGINT to write profiles cleanly.
-// Programs with more sophisticated signal handling should set
-// this to true and ensure the Stop() function returned from Start()
-// is called during shutdown.
-func NoShutdownHook(p *Profile) { p.noShutdownHook = true }
-
-// Quiet suppresses informational messages during profiling.
-func Quiet(p *Profile) { p.quiet = true }
-
-// CPUProfile enables cpu profiling.
-// It disables any previous profiling settings.
-func CPUProfile(p *Profile) { p.mode = cpuMode }
-
-// DefaultMemProfileRate is the default memory profiling rate.
-// See also http://golang.org/pkg/runtime/#pkg-variables
-const DefaultMemProfileRate = 4096
-
-// MemProfile enables memory profiling.
-// It disables any previous profiling settings.
-func MemProfile(p *Profile) {
-	p.memProfileRate = DefaultMemProfileRate
-	p.mode = memMode
-}
-
-// MemProfileRate enables memory profiling at the preferred rate.
-// It disables any previous profiling settings.
-func MemProfileRate(rate int) func(*Profile) {
-	return func(p *Profile) {
-		p.memProfileRate = rate
-		p.mode = memMode
-	}
-}
-
-// MutexProfile enables mutex profiling.
-// It disables any previous profiling settings.
-//
-// Mutex profiling is a no-op before go1.8.
-func MutexProfile(p *Profile) { p.mode = mutexMode }
-
-// BlockProfile enables block (contention) profiling.
-// It disables any previous profiling settings.
-func BlockProfile(p *Profile) { p.mode = blockMode }
-
-// Trace profile controls if execution tracing will be enabled. It disables any previous profiling settings.
-func TraceProfile(p *Profile) { p.mode = traceMode }
-
-// ProfilePath controls the base path where various profiling
-// files are written. If blank, the base path will be generated
-// by ioutil.TempDir.
-func ProfilePath(path string) func(*Profile) {
-	return func(p *Profile) {
-		p.path = path
-	}
-}
-
-// Stop stops the profile and flushes any unwritten data.
-func (p *Profile) Stop() {
-	if !atomic.CompareAndSwapUint32(&p.stopped, 0, 1) {
-		// someone has already called close
-		return
-	}
-	p.closer()
-	atomic.StoreUint32(&started, 0)
-}
-
-// started is non zero if a profile is running.
-var started uint32
-
-// Start starts a new profiling session.
-// The caller should call the Stop method on the value returned
-// to cleanly stop profiling.
-func Start(options ...func(*Profile)) interface {
-	Stop()
-} {
-	if !atomic.CompareAndSwapUint32(&started, 0, 1) {
-		log.Fatal("profile: Start() already called")
-	}
-
-	var prof Profile
-	for _, option := range options {
-		option(&prof)
-	}
-
-	path, err := func() (string, error) {
-		if p := prof.path; p != "" {
-			return p, os.MkdirAll(p, 0777)
-		}
-		return ioutil.TempDir("", "profile")
-	}()
-
-	if err != nil {
-		log.Fatalf("profile: could not create initial output directory: %v", err)
-	}
-
-	logf := func(format string, args ...interface{}) {
-		if !prof.quiet {
-			log.Printf(format, args...)
-		}
-	}
-
-	switch prof.mode {
-	case cpuMode:
-		fn := filepath.Join(path, "cpu.pprof")
-		f, err := os.Create(fn)
-		if err != nil {
-			log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
-		}
-		logf("profile: cpu profiling enabled, %s", fn)
-		pprof.StartCPUProfile(f)
-		prof.closer = func() {
-			pprof.StopCPUProfile()
-			f.Close()
-			logf("profile: cpu profiling disabled, %s", fn)
-		}
-
-	case memMode:
-		fn := filepath.Join(path, "mem.pprof")
-		f, err := os.Create(fn)
-		if err != nil {
-			log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
-		}
-		old := runtime.MemProfileRate
-		runtime.MemProfileRate = prof.memProfileRate
-		logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
-		prof.closer = func() {
-			pprof.Lookup("heap").WriteTo(f, 0)
-			f.Close()
-			runtime.MemProfileRate = old
-			logf("profile: memory profiling disabled, %s", fn)
-		}
-
-	case mutexMode:
-		fn := filepath.Join(path, "mutex.pprof")
-		f, err := os.Create(fn)
-		if err != nil {
-			log.Fatalf("profile: could not create mutex profile %q: %v", fn, err)
-		}
-		enableMutexProfile()
-		logf("profile: mutex profiling enabled, %s", fn)
-		prof.closer = func() {
-			if mp := pprof.Lookup("mutex"); mp != nil {
-				mp.WriteTo(f, 0)
-			}
-			f.Close()
-			disableMutexProfile()
-			logf("profile: mutex profiling disabled, %s", fn)
-		}
-
-	case blockMode:
-		fn := filepath.Join(path, "block.pprof")
-		f, err := os.Create(fn)
-		if err != nil {
-			log.Fatalf("profile: could not create block profile %q: %v", fn, err)
-		}
-		runtime.SetBlockProfileRate(1)
-		logf("profile: block profiling enabled, %s", fn)
-		prof.closer = func() {
-			pprof.Lookup("block").WriteTo(f, 0)
-			f.Close()
-			runtime.SetBlockProfileRate(0)
-			logf("profile: block profiling disabled, %s", fn)
-		}
-
-	case traceMode:
-		fn := filepath.Join(path, "trace.out")
-		f, err := os.Create(fn)
-		if err != nil {
-			log.Fatalf("profile: could not create trace output file %q: %v", fn, err)
-		}
-		if err := startTrace(f); err != nil {
-			log.Fatalf("profile: could not start trace: %v", err)
-		}
-		logf("profile: trace enabled, %s", fn)
-		prof.closer = func() {
-			stopTrace()
-			logf("profile: trace disabled, %s", fn)
-		}
-	}
-
-	if !prof.noShutdownHook {
-		go func() {
-			c := make(chan os.Signal, 1)
-			signal.Notify(c, os.Interrupt)
-			<-c
-
-			log.Println("profile: caught interrupt, stopping profiles")
-			prof.Stop()
-
-			os.Exit(0)
-		}()
-	}
-
-	return &prof
-}
diff --git a/vendor/github.com/pkg/profile/trace.go b/vendor/github.com/pkg/profile/trace.go
deleted file mode 100644
index b349ed8b..00000000
--- a/vendor/github.com/pkg/profile/trace.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// +build go1.7
-
-package profile
-
-import "runtime/trace"
-
-var startTrace = trace.Start
-var stopTrace = trace.Stop
diff --git a/vendor/github.com/pkg/profile/trace16.go b/vendor/github.com/pkg/profile/trace16.go
deleted file mode 100644
index 6aa6566e..00000000
--- a/vendor/github.com/pkg/profile/trace16.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// +build !go1.7
-
-package profile
-
-import "io"
-
-// mock trace support for Go 1.6 and earlier.
-
-func startTrace(w io.Writer) error { return nil }
-func stopTrace()                   {}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index f89093d3..ccde4992 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -18,8 +18,6 @@ github.com/mattn/go-colorable
 github.com/mattn/go-isatty
 # github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b
 github.com/peterh/liner
-# github.com/pkg/profile v0.0.0-20170413231811-06b906832ed0
-github.com/pkg/profile
 # github.com/russross/blackfriday v1.5.2
 github.com/russross/blackfriday
 # github.com/sirupsen/logrus v1.6.0


Test patch:
diff --git a/_fixtures/buildflagtest.go b/_fixtures/buildflagtest.go
new file mode 100644
index 00000000..92ae8c5e
--- /dev/null
+++ b/_fixtures/buildflagtest.go
@@ -0,0 +1,14 @@
+package main
+
+import "fmt"
+
+// To be set via
+//   go build -ldflags '-X main.Hello=World'
+var Hello string
+
+func main() {
+	if len(Hello) < 1 {
+		panic("global main.Hello not set via build flags")
+	}
+	fmt.Printf("Hello %s!\n", Hello)
+}
diff --git a/_fixtures/testvariablescgo/test.c b/_fixtures/testvariablescgo/test.c
new file mode 100644
index 00000000..2299e142
--- /dev/null
+++ b/_fixtures/testvariablescgo/test.c
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef __amd64__
+#define BREAKPOINT asm("int3;")
+#elif __i386__
+#define BREAKPOINT asm("int3;")
+#elif __aarch64__
+#define BREAKPOINT asm("brk 0;")
+#endif
+
+#define N 100
+
+struct align_check {
+	int a;
+	char b;
+};
+
+void testfn(void) {
+	const char *s0 = "a string";
+	const char *longstring = "averylongstring0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g0123456789h0123456789";
+	int *v = malloc(sizeof(int) * N);
+	struct align_check *v_align_check = malloc(sizeof(struct align_check) * N);
+
+	for (int i = 0; i < N; i++) {
+		v[i] = i;
+		v_align_check[i].a = i;
+		v_align_check[i].b = i;
+	}
+
+	char *s = malloc(strlen(s0) + 1);
+	strcpy(s, s0);
+
+	BREAKPOINT;
+	
+	printf("%s %s %p %p\n", s, longstring, v, v_align_check);
+}
diff --git a/_fixtures/testvariablescgo/testvariablescgo.go b/_fixtures/testvariablescgo/testvariablescgo.go
new file mode 100644
index 00000000..be4e199b
--- /dev/null
+++ b/_fixtures/testvariablescgo/testvariablescgo.go
@@ -0,0 +1,11 @@
+package main
+
+// #cgo CFLAGS: -g -Wall -O0 -std=gnu99
+/*
+extern void testfn(void);
+*/
+import "C"
+
+func main() {
+	C.testfn()
+}
diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go
index ef49b582..f4725801 100644
--- a/cmd/dlv/dlv_test.go
+++ b/cmd/dlv/dlv_test.go
@@ -628,6 +628,52 @@ func TestTrace(t *testing.T) {
 	cmd.Wait()
 }
 
+func TestTracePid(t *testing.T) {
+	if runtime.GOOS == "linux" {
+		bs, _ := ioutil.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
+		if bs == nil || strings.TrimSpace(string(bs)) != "0" {
+			t.Logf("can not run TestAttachDetach: %v\n", bs)
+			return
+		}
+	}
+
+	dlvbin, tmpdir := getDlvBin(t)
+	defer os.RemoveAll(tmpdir)
+
+	expected := []byte("goroutine(1): main.A() => ()\n")
+
+	// make process run
+	fix := protest.BuildFixture("issue2023", 0)
+	targetCmd := exec.Command(fix.Path)
+	if err := targetCmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+	if targetCmd.Process == nil || targetCmd.Process.Pid == 0 {
+		t.Fatal("expected target process runninng")
+	}
+	defer targetCmd.Process.Kill()
+
+	// dlv attach the process by pid
+	cmd := exec.Command(dlvbin, "trace", "-p", strconv.Itoa(targetCmd.Process.Pid), "main.A")
+	rdr, err := cmd.StderrPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = cmd.Start()
+	if err != nil {
+		t.Fatalf("error running trace: %#v", err)
+	}
+	output, err := ioutil.ReadAll(rdr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Contains(output, expected) {
+		t.Fatalf("expected:\n%s\ngot:\n%s", string(expected), string(output))
+	}
+
+	cmd.Wait()
+}
+
 func TestTraceBreakpointExists(t *testing.T) {
 	dlvbin, tmpdir := getDlvBin(t)
 	defer os.RemoveAll(tmpdir)
diff --git a/pkg/dwarf/frame/parser_test.go b/pkg/dwarf/frame/parser_test.go
index d03ea01c..ce6c9e50 100644
--- a/pkg/dwarf/frame/parser_test.go
+++ b/pkg/dwarf/frame/parser_test.go
@@ -6,8 +6,6 @@ import (
 	"io/ioutil"
 	"os"
 	"testing"
-
-	"github.com/pkg/profile"
 )
 
 func TestParseCIE(t *testing.T) {
@@ -42,7 +40,6 @@ func TestParseCIE(t *testing.T) {
 }
 
 func BenchmarkParse(b *testing.B) {
-	defer profile.Start(profile.CPUProfile).Stop()
 	f, err := os.Open("testdata/frame")
 	if err != nil {
 		b.Fatal(err)
diff --git a/pkg/dwarf/line/line_parser_test.go b/pkg/dwarf/line/line_parser_test.go
index d2e3ba5b..f5d0901e 100644
--- a/pkg/dwarf/line/line_parser_test.go
+++ b/pkg/dwarf/line/line_parser_test.go
@@ -17,7 +17,6 @@ import (
 	"unsafe"
 
 	"github.com/go-delve/delve/pkg/dwarf/godwarf"
-	"github.com/pkg/profile"
 )
 
 var userTestFile string
@@ -163,7 +162,6 @@ func TestDebugLinePrologueParser(t *testing.T) {
 }
 
 func BenchmarkLineParser(b *testing.B) {
-	defer profile.Start(profile.MemProfile).Stop()
 	p, err := filepath.Abs("../../../_fixtures/testnextprog")
 	if err != nil {
 		b.Fatal(err)
@@ -277,10 +275,8 @@ func runTestPCToLine(t testing.TB, lineInfos DebugLines, entries []pctolineEntry
 				t.Fatalf("Mismatch at PC %#x, expected %s:%d got %s:%d", pc, entries[i].file, entries[i].line, file, line)
 			}
 			i++
-		} else {
-			if !entries[i-1].match(file, line) {
-				t.Fatalf("Mismatch at PC %#x, expected %s:%d (from previous valid entry) got %s:%d", pc, entries[i-1].file, entries[i-1].line, file, line)
-			}
+		} else if !entries[i-1].match(file, line) {
+			t.Fatalf("Mismatch at PC %#x, expected %s:%d (from previous valid entry) got %s:%d", pc, entries[i-1].file, entries[i-1].line, file, line)
 		}
 	}
 }
diff --git a/pkg/proc/gdbserial/rr_test.go b/pkg/proc/gdbserial/rr_test.go
index e949b67a..eed5ec54 100644
--- a/pkg/proc/gdbserial/rr_test.go
+++ b/pkg/proc/gdbserial/rr_test.go
@@ -49,7 +49,7 @@ func assertNoError(err error, t testing.TB, s string) {
 	}
 }
 
-func setFunctionBreakpoint(p proc.Process, t *testing.T, fname string) *proc.Breakpoint {
+func setFunctionBreakpoint(p *proc.Target, t *testing.T, fname string) *proc.Breakpoint {
 	_, f, l, _ := runtime.Caller(1)
 	f = filepath.Base(f)
 
@@ -117,7 +117,7 @@ func TestRestartDuringStop(t *testing.T) {
 	})
 }
 
-func setFileBreakpoint(p proc.Process, t *testing.T, fixture protest.Fixture, lineno int) *proc.Breakpoint {
+func setFileBreakpoint(p *proc.Target, t *testing.T, fixture protest.Fixture, lineno int) *proc.Breakpoint {
 	_, f, l, _ := runtime.Caller(1)
 	f = filepath.Base(f)
 
diff --git a/pkg/proc/proc_general_test.go b/pkg/proc/proc_general_test.go
index 2e35469d..9ff21608 100644
--- a/pkg/proc/proc_general_test.go
+++ b/pkg/proc/proc_general_test.go
@@ -24,3 +24,73 @@ func TestIssue554(t *testing.T) {
 		t.Fatalf("should be false")
 	}
 }
+
+type dummyMem struct {
+	t     *testing.T
+	mem   []byte
+	base  uint64
+	reads []memRead
+}
+
+type memRead struct {
+	addr uint64
+	size int
+}
+
+func (dm *dummyMem) ReadMemory(buf []byte, addr uintptr) (int, error) {
+	dm.t.Logf("read addr=%#x size=%#x\n", addr, len(buf))
+	dm.reads = append(dm.reads, memRead{uint64(addr), len(buf)})
+	a := int64(addr) - int64(dm.base)
+	if a < 0 {
+		panic("reading below base")
+	}
+	if int(a)+len(buf) > len(dm.mem) {
+		panic("reading beyond end of mem")
+	}
+	copy(buf, dm.mem[a:])
+	return len(buf), nil
+}
+
+func (dm *dummyMem) WriteMemory(uintptr, []byte) (int, error) {
+	panic("not supported")
+}
+
+func TestReadCStringValue(t *testing.T) {
+	const tgt = "a test string"
+	const maxstrlen = 64
+
+	dm := &dummyMem{t: t}
+	dm.mem = make([]byte, maxstrlen)
+	copy(dm.mem, tgt)
+
+	for _, tc := range []struct {
+		base     uint64
+		numreads int
+	}{
+		{0x5000, 1},
+		{0x5001, 1},
+		{0x4fff, 2},
+		{uint64(0x5000 - len(tgt) - 1), 1},
+		{uint64(0x5000-len(tgt)-1) + 1, 2},
+	} {
+		t.Logf("base is %#x\n", tc.base)
+		dm.base = tc.base
+		dm.reads = dm.reads[:0]
+		out, done, err := readCStringValue(dm, uintptr(tc.base), LoadConfig{MaxStringLen: maxstrlen})
+		if err != nil {
+			t.Errorf("base=%#x readCStringValue: %v", tc.base, err)
+		}
+		if !done {
+			t.Errorf("base=%#x expected done but wasn't", tc.base)
+		}
+		if out != tgt {
+			t.Errorf("base=%#x got %q expected %q", tc.base, out, tgt)
+		}
+		if len(dm.reads) != tc.numreads {
+			t.Errorf("base=%#x wrong number of reads %d (expected %d)", tc.base, len(dm.reads), tc.numreads)
+		}
+		if tc.base == 0x4fff && dm.reads[0].size != 1 {
+			t.Errorf("base=%#x first read in not of one byte", tc.base)
+		}
+	}
+}
diff --git a/service/dap/server_test.go b/service/dap/server_test.go
index d020f16e..ff86808b 100644
--- a/service/dap/server_test.go
+++ b/service/dap/server_test.go
@@ -345,7 +345,8 @@ func runDebugSession(t *testing.T, client *daptest.Client, launchRequest func())
 
 func TestLaunchDebugRequest(t *testing.T) {
 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
-		// We reuse the harness that builds, but ignore the actual binary.
+		// We reuse the harness that builds, but ignore the built binary,
+		// only relying on the source to be built in response to LaunchRequest.
 		runDebugSession(t, client, func() {
 			// Use the default output directory.
 			client.LaunchRequestWithArgs(map[string]interface{}{
@@ -357,7 +358,8 @@ func TestLaunchDebugRequest(t *testing.T) {
 func TestLaunchTestRequest(t *testing.T) {
 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
 		runDebugSession(t, client, func() {
-			// We reuse the harness that builds, but ignore the actual binary.
+			// We reuse the harness that builds, but ignore the built binary,
+			// only relying on the source to be built in response to LaunchRequest.
 			fixtures := protest.FindFixturesDir()
 			testdir, _ := filepath.Abs(filepath.Join(fixtures, "buildtest"))
 			client.LaunchRequestWithArgs(map[string]interface{}{
@@ -366,6 +368,10 @@ func TestLaunchTestRequest(t *testing.T) {
 	})
 }
 
+// Tests that 'args' from LaunchRequest are parsed and passed to the target
+// program. The target program exits without an error on success, and
+// panics on error, causing an unexpected StoppedEvent instead of
+// Terminated Event.
 func TestLaunchRequestWithArgs(t *testing.T) {
 	runTest(t, "testargs", func(client *daptest.Client, fixture protest.Fixture) {
 		runDebugSession(t, client, func() {
@@ -376,6 +382,22 @@ func TestLaunchRequestWithArgs(t *testing.T) {
 	})
 }
 
+// Tests that 'buildFlags' from LaunchRequest are parsed and passed to the
+// compiler. The target program exits without an error on success, and
+// panics on error, causing an unexpected StoppedEvent instead of
+// TerminatedEvent.
+func TestLaunchRequestWithBuildFlags(t *testing.T) {
+	runTest(t, "buildflagtest", func(client *daptest.Client, fixture protest.Fixture) {
+		runDebugSession(t, client, func() {
+			// We reuse the harness that builds, but ignore the built binary,
+			// only relying on the source to be built in response to LaunchRequest.
+			client.LaunchRequestWithArgs(map[string]interface{}{
+				"mode": "debug", "program": fixture.Source,
+				"buildFlags": "-ldflags '-X main.Hello=World'"})
+		})
+	})
+}
+
 func TestUnupportedCommandResponses(t *testing.T) {
 	var got *dap.ErrorResponse
 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
@@ -586,6 +608,10 @@ func TestBadLaunchRequests(t *testing.T) {
 		expectFailedToLaunchWithMessage(client.ExpectErrorResponse(t),
 			"Failed to launch: value '1' in 'args' attribute in debug configuration is not a string.")
 
+		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "buildFlags": 123})
+		expectFailedToLaunchWithMessage(client.ExpectErrorResponse(t),
+			"Failed to launch: 'buildFlags' attribute '123' in debug configuration is not a string.")
+
 		// Skip detailed message checks for potentially different OS-specific errors.
 		client.LaunchRequest("exec", fixture.Path+"_does_not_exist", stopOnEntry)
 		expectFailedToLaunch(client.ExpectErrorResponse(t))
@@ -596,6 +622,9 @@ func TestBadLaunchRequests(t *testing.T) {
 		client.LaunchRequest("exec", fixture.Source, stopOnEntry)
 		expectFailedToLaunch(client.ExpectErrorResponse(t)) // Not an executable
 
+		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "buildFlags": "123"})
+		expectFailedToLaunch(client.ExpectErrorResponse(t)) // Build error
+
 		// We failed to launch the program. Make sure shutdown still works.
 		client.DisconnectRequest()
 		dresp := client.ExpectDisconnectResponse(t)
diff --git a/service/test/integration2_test.go b/service/test/integration2_test.go
index e62720ed..f532cfe7 100644
--- a/service/test/integration2_test.go
+++ b/service/test/integration2_test.go
@@ -3,6 +3,7 @@ package service_test
 import (
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"math/rand"
 	"net"
 	"net/rpc"
@@ -74,6 +75,9 @@ func startServer(name string, buildFlags protest.BuildFlags, t *testing.T) (clie
 		Debugger: debugger.Config{
 			Backend:        testBackend,
 			CheckGoVersion: true,
+			Packages:       []string{fixture.Source},
+			BuildFlags:     "", // build flags can be an empty string here because the only test that uses it, does not set special flags.
+			ExecuteKind:    debugger.ExecutingGeneratedFile,
 		},
 	})
 	if err := server.Run(); err != nil {
@@ -109,7 +113,8 @@ func TestRunWithInvalidPath(t *testing.T) {
 		ProcessArgs: []string{"invalid_path"},
 		APIVersion:  2,
 		Debugger: debugger.Config{
-			Backend: testBackend,
+			Backend:     testBackend,
+			ExecuteKind: debugger.ExecutingGeneratedFile,
 		},
 	})
 	if err := server.Run(); err == nil {
@@ -124,7 +129,7 @@ func TestRestart_afterExit(t *testing.T) {
 		if !state.Exited {
 			t.Fatal("expected initial process to have exited")
 		}
-		if _, err := c.Restart(); err != nil {
+		if _, err := c.Restart(false); err != nil {
 			t.Fatal(err)
 		}
 		if c.ProcessPid() == origPid {
@@ -154,7 +159,7 @@ func TestRestart_breakpointPreservation(t *testing.T) {
 		}
 
 		t.Log("Restart")
-		c.Restart()
+		c.Restart(false)
 		stateCh = c.Continue()
 		state = <-stateCh
 		if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint {
@@ -178,7 +183,7 @@ func TestRestart_duringStop(t *testing.T) {
 		if state.CurrentThread.Breakpoint == nil {
 			t.Fatal("did not hit breakpoint")
 		}
-		if _, err := c.Restart(); err != nil {
+		if _, err := c.Restart(false); err != nil {
 			t.Fatal(err)
 		}
 		if c.ProcessPid() == origPid {
@@ -194,6 +199,72 @@ func TestRestart_duringStop(t *testing.T) {
 	})
 }
 
+// This source is a slightly modified version of
+// _fixtures/testenv.go. The only difference is that
+// the name of the environment variable we are trying to
+// read is named differently, so we can assert the code
+// was actually changed in the test.
+const modifiedSource = `package main
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+)
+
+func main() {
+	x := os.Getenv("SOMEMODIFIEDVAR")
+	runtime.Breakpoint()
+	fmt.Printf("SOMEMODIFIEDVAR=%s\n", x)
+}
+`
+
+func TestRestart_rebuild(t *testing.T) {
+	// In the original fixture file the env var tested for is SOMEVAR.
+	os.Setenv("SOMEVAR", "bah")
+
+	withTestClient2Extended("testenv", t, 0, func(c service.Client, f protest.Fixture) {
+		<-c.Continue()
+
+		var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "x", normalLoadConfig)
+		assertNoError(err, t, "EvalVariable")
+
+		if var1.Value != "bah" {
+			t.Fatalf("expected 'bah' got %q", var1.Value)
+		}
+
+		fi, err := os.Stat(f.Source)
+		assertNoError(err, t, "Stat fixture.Source")
+
+		originalSource, err := ioutil.ReadFile(f.Source)
+		assertNoError(err, t, "Reading original source")
+
+		// Ensure we write the original source code back after the test exits.
+		defer ioutil.WriteFile(f.Source, originalSource, fi.Mode())
+
+		// Write modified source code to the fixture file.
+		err = ioutil.WriteFile(f.Source, []byte(modifiedSource), fi.Mode())
+		assertNoError(err, t, "Writing modified source")
+
+		// First set our new env var and ensure later that the
+		// modified source code picks it up.
+		os.Setenv("SOMEMODIFIEDVAR", "foobar")
+
+		// Restart the program, rebuilding from source.
+		_, err = c.Restart(true)
+		assertNoError(err, t, "Restart(true)")
+
+		<-c.Continue()
+
+		var1, err = c.EvalVariable(api.EvalScope{GoroutineID: -1}, "x", normalLoadConfig)
+		assertNoError(err, t, "EvalVariable")
+
+		if var1.Value != "foobar" {
+			t.Fatalf("expected 'foobar' got %q", var1.Value)
+		}
+	})
+}
+
 func TestClientServer_exit(t *testing.T) {
 	protest.AllowRecording(t)
 	withTestClient2("continuetestprog", t, func(c service.Client) {
@@ -1350,7 +1421,7 @@ func TestClientServer_RestartBreakpointPosition(t *testing.T) {
 		}
 		_, err = c.Halt()
 		assertNoError(err, t, "Halt")
-		_, err = c.Restart()
+		_, err = c.Restart(false)
 		assertNoError(err, t, "Restart")
 		bps, err := c.ListBreakpoints()
 		assertNoError(err, t, "ListBreakpoints")
@@ -1574,7 +1645,8 @@ func TestAcceptMulticlient(t *testing.T) {
 			AcceptMulti:    true,
 			DisconnectChan: disconnectChan,
 			Debugger: debugger.Config{
-				Backend: testBackend,
+				Backend:     testBackend,
+				ExecuteKind: debugger.ExecutingGeneratedTest,
 			},
 		})
 		if err := server.Run(); err != nil {
@@ -1826,7 +1898,7 @@ func TestRerecord(t *testing.T) {
 
 		t0 := gett()
 
-		_, err = c.RestartFrom(false, "", false, nil)
+		_, err = c.RestartFrom(false, "", false, nil, false)
 		assertNoError(err, t, "First restart")
 		t1 := gett()
 
@@ -1836,7 +1908,7 @@ func TestRerecord(t *testing.T) {
 
 		time.Sleep(2 * time.Second) // make sure that we're not running inside the same second
 
-		_, err = c.RestartFrom(true, "", false, nil)
+		_, err = c.RestartFrom(true, "", false, nil, false)
 		assertNoError(err, t, "Second restart")
 		t2 := gett()
 
@@ -1901,7 +1973,7 @@ func TestStopRecording(t *testing.T) {
 
 		// try rerecording
 		go func() {
-			c.RestartFrom(true, "", false, nil)
+			c.RestartFrom(true, "", false, nil, false)
 		}()
 
 		time.Sleep(time.Second) // hopefully the re-recording started...
diff --git a/service/test/variables_test.go b/service/test/variables_test.go
index 61b544b6..657c81dc 100644
--- a/service/test/variables_test.go
+++ b/service/test/variables_test.go
@@ -1519,3 +1519,46 @@ func TestPluginVariables(t *testing.T) {
 		assertVariable(t, vb, varTest{"b", true, `github.com/go-delve/delve/_fixtures/internal/pluginsupport.SomethingElse(*github.com/go-delve/delve/_fixtures/plugin2.asomethingelse) *{x: 1, y: 4}`, ``, `github.com/go-delve/delve/_fixtures/internal/pluginsupport.SomethingElse`, nil})
 	})
 }
+
+func TestCgoEval(t *testing.T) {
+	testcases := []varTest{
+		{"s", true, `"a string"`, `"a string"`, "*char", nil},
+		{"longstring", true, `"averylongstring0123456789a0123456789b0123456789c0123456789d01234...+1 more"`, `"averylongstring0123456789a0123456789b0123456789c0123456789d01234...+1 more"`, "*const char", nil},
+		{"longstring[64:]", false, `"56789e0123456789f0123456789g0123456789h0123456789"`, `"56789e0123456789f0123456789g0123456789h0123456789"`, "*const char", nil},
+		{"s[3]", false, "116", "116", "char", nil},
+		{"v", true, "*0", "(*int)(…", "*int", nil},
+		{"v[1]", false, "1", "1", "int", nil},
+		{"v[90]", false, "90", "90", "int", nil},
+		{"v[:5]", false, "[]int len: 5, cap: 5, [0,1,2,3,4]", "[]int len: 5, cap: 5, [...]", "[]int", nil},
+		{"v_align_check", true, "*align_check {a: 0, b: 0}", "(*struct align_check)(…", "*struct align_check", nil},
+		{"v_align_check[1]", false, "align_check {a: 1, b: 1}", "align_check {a: 1, b: 1}", "align_check", nil},
+		{"v_align_check[90]", false, "align_check {a: 90, b: 90}", "align_check {a: 90, b: 90}", "align_check", nil},
+	}
+
+	protest.AllowRecording(t)
+	withTestProcess("testvariablescgo/", t, func(p *proc.Target, fixture protest.Fixture) {
+		assertNoError(p.Continue(), t, "Continue() returned an error")
+		for _, tc := range testcases {
+			variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
+			if err != nil && err.Error() == "evaluating methods not supported on this version of Go" {
+				// this type of eval is unsupported with the current version of Go.
+				continue
+			}
+			if tc.err == nil {
+				assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name))
+				assertVariable(t, variable, tc)
+				variable, err := evalVariable(p, tc.name, pshortLoadConfig)
+				assertNoError(err, t, fmt.Sprintf("EvalExpression(%s, pshortLoadConfig) returned an error", tc.name))
+				assertVariable(t, variable, tc.alternateVarTest())
+			} else {
+				if err == nil {
+					t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
+				}
+				if tc.err.Error() != err.Error() {
+					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
+				}
+			}
+
+		}
+	})
+}