Repository: go-delve/delve
Pull request #1858 (2020-02-11 20:36:32)

service/dap: Initial implementation for 'dlv dap'
This change adds an initial synchronous implementation for running delve over DAP that supports a handful of requests (initialize, launch, set breakpoint, continue, disconnect). This min viable version is lacking support for many requests and other features (see comments in the code), but this should be enough to agree on the overall approach before diving into more details. (I do plan to add more tests to service_test and dlv_test in future PRs.)

Updates #1515

polinasok: Hmm, it appears that the tests are behaving differently here than they did for me locally. Investigating.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e33d2baa..f48e1f0f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ This project adheres to Semantic Versioning.
 
 All changes mention the author, unless contributed by me (@derekparker).
 
-## [1.4.0] 2019-02-11
+## [1.4.0] 2020-02-11
 
 ### Added
 
diff --git a/Documentation/cli/README.md b/Documentation/cli/README.md
index 847e32e0..32da2428 100644
--- a/Documentation/cli/README.md
+++ b/Documentation/cli/README.md
@@ -1,11 +1,8 @@
-# Configuration
+# Configuration and Command History
 
-Delve can be configured via the configuration file located in `$HOME/.config/dlv/config.yml`.
-You can open the file and discover all the configurable options and their default value.
+If `$XDG_CONFIG_HOME` is set, then configuration and command history files are located in `$XDG_CONFIG_HOME/dlv`. Otherwise, they are located in `$HOME/.config/dlv` on Linux and `$HOME/.dlv` on other systems.
 
-# History
-
-The command history of delve debugger is stored in `$HOME/.config/dlv/.dbg_history`.
+The configuration file `config.yml` contains all the configurable options and their default values. The command history is stored in `.dbg_history`.
 
 # Commands
 
@@ -27,6 +24,7 @@ Command | Description
 [disassemble](#disassemble) | Disassembler.
 [down](#down) | Move the current frame down.
 [edit](#edit) | Open where you are in $DELVE_EDITOR or $EDITOR
+[examinemem](#examinemem) | Examine memory:
 [exit](#exit) | Exit the debugger.
 [frame](#frame) | Set the current frame, or execute command on a different frame.
 [funcs](#funcs) | Print list of functions.
@@ -213,6 +211,18 @@ If locspec is omitted edit will open the current source file in the editor, othe
 
 Aliases: ed
 
+## examinemem
+Examine memory:
+
+    examinemem [-fmt <format>] [-len <length>] <address>
+
+Format represents the data format and the value is one of this list (default hex): oct(octal), hex(hexadecimal), dec(decimal), bin(binary).
+Length is the number of bytes (default 1) and must be less than or equal to 1000.
+Address is the memory location of the target to examine.
+For example:  x -fmt hex -len 20 0xc00008af38
+
+Aliases: x
+
 ## exit
 Exit the debugger.
 		
diff --git a/Documentation/cli/starlark.md b/Documentation/cli/starlark.md
index 6e173f30..193a89c5 100644
--- a/Documentation/cli/starlark.md
+++ b/Documentation/cli/starlark.md
@@ -29,6 +29,7 @@ create_breakpoint(Breakpoint) | Equivalent to API call [CreateBreakpoint](https:
 detach(Kill) | Equivalent to API call [Detach](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Detach)
 disassemble(Scope, StartPC, EndPC, Flavour) | Equivalent to API call [Disassemble](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Disassemble)
 eval(Scope, Expr, Cfg) | Equivalent to API call [Eval](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Eval)
+examine_memory(Address, Length) | Equivalent to API call [ExamineMemory](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ExamineMemory)
 find_location(Scope, Loc, IncludeNonExecutableLines) | Equivalent to API call [FindLocation](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.FindLocation)
 function_return_locations(FnName) | Equivalent to API call [FunctionReturnLocations](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.FunctionReturnLocations)
 get_breakpoint(Id, Name) | Equivalent to API call [GetBreakpoint](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.GetBreakpoint)
diff --git a/Documentation/usage/dlv.md b/Documentation/usage/dlv.md
index 5d5376e3..e10abdc3 100644
--- a/Documentation/usage/dlv.md
+++ b/Documentation/usage/dlv.md
@@ -38,6 +38,7 @@ Pass flags to the program you are debugging using `--`, for example:
 * [dlv attach](dlv_attach.md)	 - Attach to running process and begin debugging.
 * [dlv connect](dlv_connect.md)	 - Connect to a headless debug server.
 * [dlv core](dlv_core.md)	 - Examine a core dump.
+* [dlv dap](dlv_dap.md)	 - [EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
 * [dlv debug](dlv_debug.md)	 - Compile and begin debugging main package in current directory, or the package specified.
 * [dlv exec](dlv_exec.md)	 - Execute a precompiled binary, and begin a debug session.
 * [dlv replay](dlv_replay.md)	 - Replays a rr trace.
diff --git a/Documentation/usage/dlv_dap.md b/Documentation/usage/dlv_dap.md
new file mode 100644
index 00000000..4cbc18ac
--- /dev/null
+++ b/Documentation/usage/dlv_dap.md
@@ -0,0 +1,41 @@
+## dlv dap
+
+[EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
+
+### Synopsis
+
+
+[EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
+
+The server supports debugging of a precompiled binary akin to 'dlv exec' via a launch request.
+It does not yet support support specification of program arguments.
+It does not yet support launch requests with 'debug' and 'test' modes that require compilation.
+It does not yet support attach requests to debug a running process like with 'dlv attach'.
+It does not yet support asynchronous request-response communication.
+The server does not accept multiple client connections.
+
+```
+dlv dap
+```
+
+### Options inherited from parent commands
+
+```
+      --accept-multiclient   Allows a headless server to accept multiple client connections.
+      --api-version int      Selects API version when headless. (default 1)
+      --backend string       Backend selection (see 'dlv help backend'). (default "default")
+      --build-flags string   Build flags, to be passed to the compiler.
+      --check-go-version     Checks that the version of Go in use is compatible with Delve. (default true)
+      --headless             Run debug server only, in headless mode.
+      --init string          Init file, executed by the terminal client.
+  -l, --listen string        Debugging server listen address. (default "127.0.0.1:0")
+      --log                  Enable debugging server logging.
+      --log-dest string      Writes logs to the specified file or file descriptor (see 'dlv help log').
+      --log-output string    Comma separated list of components that should produce debug output (see 'dlv help log')
+      --only-same-user       Only connections from the same user that started this instance of Delve are allowed to connect. (default true)
+      --wd string            Working directory for running the program. (default ".")
+```
+
+### SEE ALSO
+* [dlv](dlv.md)	 - Delve is a debugger for the Go programming language.
+
diff --git a/Documentation/usage/dlv_log.md b/Documentation/usage/dlv_log.md
index 87a4016f..5f7ffa18 100644
--- a/Documentation/usage/dlv_log.md
+++ b/Documentation/usage/dlv_log.md
@@ -17,6 +17,7 @@ names selected from this list:
 	lldbout		Copy output from debugserver/lldb to standard output
 	debuglineerr	Log recoverable errors reading .debug_line
 	rpc		Log all RPC messages
+	dap		Log all DAP messages
 	fncall		Log function call protocol
 	minidump	Log minidump loading
 
@@ -24,8 +25,8 @@ Additionally --log-dest can be used to specify where the logs should be
 written. 
 If the argument is a number it will be interpreted as a file descriptor,
 otherwise as a file path.
-This option will also redirect the \"API listening\" message in headless
-mode.
+This option will also redirect the "server listening at" message in headless
+and dap modes.
 
 
 
diff --git a/_fixtures/examinememory.go b/_fixtures/examinememory.go
new file mode 100644
index 00000000..7e6dada6
--- /dev/null
+++ b/_fixtures/examinememory.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func main() {
+	l := int(51)
+	bs := make([]byte, l)
+	for i := 0; i < l; i++ {
+		bs[i] = byte(i + int(10))
+	}
+
+	bsp := (*byte)(unsafe.Pointer(&bs[0]))
+
+	bspUintptr := uintptr(unsafe.Pointer(bsp))
+
+	fmt.Printf("%#x\n", bspUintptr)
+	_ = *bsp
+
+	bs[0] = 255
+
+	_ = *bsp
+}
diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go
index 0a17860a..39726f39 100644
--- a/cmd/dlv/cmds/commands.go
+++ b/cmd/dlv/cmds/commands.go
@@ -19,6 +19,7 @@ import (
 	"github.com/go-delve/delve/pkg/version"
 	"github.com/go-delve/delve/service"
 	"github.com/go-delve/delve/service/api"
+	"github.com/go-delve/delve/service/dap"
 	"github.com/go-delve/delve/service/rpc2"
 	"github.com/go-delve/delve/service/rpccommon"
 	"github.com/spf13/cobra"
@@ -152,6 +153,22 @@ option to let the process continue or kill it.
 	}
 	RootCommand.AddCommand(connectCommand)
 
+	// 'dap' subcommand.
+	dapCommand := &cobra.Command{
+		Use:   "dap",
+		Short: "[EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).",
+		Long: `[EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
+
+The server supports debugging of a precompiled binary akin to 'dlv exec' via a launch request.
+It does not yet support support specification of program arguments.
+It does not yet support launch requests with 'debug' and 'test' modes that require compilation.
+It does not yet support attach requests to debug a running process like with 'dlv attach'.
+It does not yet support asynchronous request-response communication.
+The server does not accept multiple client connections.`,
+		Run: dapCmd,
+	}
+	RootCommand.AddCommand(dapCommand)
+
 	// 'debug' subcommand.
 	debugCommand := &cobra.Command{
 		Use:   "debug [package]",
@@ -318,6 +335,7 @@ names selected from this list:
 	lldbout		Copy output from debugserver/lldb to standard output
 	debuglineerr	Log recoverable errors reading .debug_line
 	rpc		Log all RPC messages
+	dap		Log all DAP messages
 	fncall		Log function call protocol
 	minidump	Log minidump loading
 
@@ -325,8 +343,8 @@ Additionally --log-dest can be used to specify where the logs should be
 written. 
 If the argument is a number it will be interpreted as a file descriptor,
 otherwise as a file path.
-This option will also redirect the \"API listening\" message in headless
-mode.
+This option will also redirect the "server listening at" message in headless
+and dap modes.
 
 `,
 	})
@@ -344,6 +362,63 @@ func remove(path string) {
 	}
 }
 
+func dapCmd(cmd *cobra.Command, args []string) {
+	status := func() int {
+		if err := logflags.Setup(Log, LogOutput, LogDest); err != nil {
+			fmt.Fprintf(os.Stderr, "%v\n", err)
+			return 1
+		}
+		defer logflags.Close()
+
+		if Headless {
+			fmt.Fprintf(os.Stderr, "Warning: headless mode not supported with dap\n")
+		}
+		if AcceptMulti {
+			fmt.Fprintf(os.Stderr, "Warning: accept multiclient mode not supported with dap\n")
+		}
+		if InitFile != "" {
+			fmt.Fprint(os.Stderr, "Warning: init file ignored with dap\n")
+		}
+		if ContinueOnStart {
+			fmt.Fprintf(os.Stderr, "Warning: continue ignored with dap; specify via launch/attach request instead\n")
+		}
+		if BuildFlags != "" {
+			fmt.Fprintf(os.Stderr, "Warning: build flags ignored with dap; specify via launch/attach request instead\n")
+		}
+		if WorkingDir != "" {
+			fmt.Fprintf(os.Stderr, "Warning: working directory ignored with dap; launch requests must specify full program path\n")
+		}
+		dlvArgs, targetArgs := splitArgs(cmd, args)
+		if len(dlvArgs) > 0 {
+			fmt.Fprintf(os.Stderr, "Warning: debug arguments ignored with dap; specify via launch/attach request instead\n")
+		}
+		if len(targetArgs) > 0 {
+			fmt.Fprintf(os.Stderr, "Warning: program flags ignored with dap; specify via launch/attach request instead\n")
+		}
+
+		listener, err := net.Listen("tcp", Addr)
+		if err != nil {
+			fmt.Printf("couldn't start listener: %s\n", err)
+			return 1
+		}
+		disconnectChan := make(chan struct{})
+		server := dap.NewServer(&service.Config{
+			Listener:             listener,
+			Backend:              Backend,
+			Foreground:           true, // always headless
+			DebugInfoDirectories: conf.DebugInfoDirectories,
+			CheckGoVersion:       CheckGoVersion,
+			DisconnectChan:       disconnectChan,
+		})
+		defer server.Stop()
+
+		server.Run()
+		waitForDisconnectSignal(disconnectChan)
+		return 0
+	}()
+	os.Exit(status)
+}
+
 func debugCmd(cmd *cobra.Command, args []string) {
 	status := func() int {
 		debugname, err := filepath.Abs(cmd.Flag("output").Value.String())
@@ -535,6 +610,37 @@ func connectCmd(cmd *cobra.Command, args []string) {
 	os.Exit(connect(addr, nil, conf, executingOther))
 }
 
+// waitForDisconnectSignal is a blocking function that waits for either
+// a SIGINT (Ctrl-C) signal from the OS or for disconnectChan to be closed
+// by the server when the client disconnects.
+// Note that in headless mode, the debugged process is foregrounded
+// (to have control of the tty for debugging interactive programs),
+// so SIGINT gets sent to the debuggee and not to delve.
+func waitForDisconnectSignal(disconnectChan chan struct{}) {
+	ch := make(chan os.Signal, 1)
+	signal.Notify(ch, syscall.SIGINT)
+	if runtime.GOOS == "windows" {
+		// On windows Ctrl-C sent to inferior process is delivered
+		// as SIGINT to delve. Ignore it instead of stopping the server
+		// in order to be able to debug signal handlers.
+		go func() {
+			for {
+				select {
+				case <-ch:
+				}
+			}
+		}()
+		select {
+		case <-disconnectChan:
+		}
+	} else {
+		select {
+		case <-ch:
+		case <-disconnectChan:
+		}
+	}
+}
+
 func splitArgs(cmd *cobra.Command, args []string) ([]string, []string) {
 	if cmd.ArgsLenAtDash() >= 0 {
 		return args[:cmd.ArgsLenAtDash()], args[cmd.ArgsLenAtDash():]
@@ -678,28 +784,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile
 			client = rpc2.NewClient(listener.Addr().String())
 			client.Disconnect(true) // true = continue after disconnect
 		}
-		ch := make(chan os.Signal, 1)
-		signal.Notify(ch, syscall.SIGINT)
-		if runtime.GOOS == "windows" {
-			// On windows Ctrl-C sent to inferior process is delivered
-			// as SIGINT to delve. Ignore it instead of stopping the server
-			// in order to be able to debug signal handlers.
-			go func() {
-				for {
-					select {
-					case <-ch:
-					}
-				}
-			}()
-			select {
-			case <-disconnectChan:
-			}
-		} else {
-			select {
-			case <-ch:
-			case <-disconnectChan:
-			}
-		}
+		waitForDisconnectSignal(disconnectChan)
 		err = server.Stop()
 		if err != nil {
 			fmt.Println(err)
diff --git a/go.mod b/go.mod
index 15b92091..0d8006f5 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.11
 require (
 	github.com/cosiner/argv v0.0.0-20170225145430-13bacc38a0a5
 	github.com/cpuguy83/go-md2man v1.0.8 // indirect
+	github.com/google/go-dap v0.1.0
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
 	github.com/kr/pretty v0.1.0 // indirect
 	github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561
diff --git a/go.sum b/go.sum
index 80729476..a811d1fc 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/go-dap v0.1.0 h1:UzVzngq6yBR+bJVnTM8mjcdKrQnYR7m7U7JpNSnEo48=
+github.com/google/go-dap v0.1.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
diff --git a/pkg/logflags/logflags.go b/pkg/logflags/logflags.go
index 0e1aad77..ed810704 100644
--- a/pkg/logflags/logflags.go
+++ b/pkg/logflags/logflags.go
@@ -21,6 +21,7 @@ var gdbWire = false
 var lldbServerOutput = false
 var debugLineErrors = false
 var rpc = false
+var dap = false
 var fnCall = false
 var minidump = false
 
@@ -34,7 +35,7 @@ func makeLogger(flag bool, fields logrus.Fields) *logrus.Entry {
 	}
 	logger.Logger.Level = logrus.DebugLevel
 	if !flag {
-		logger.Logger.Level = logrus.PanicLevel
+		logger.Logger.Level = logrus.ErrorLevel
 	}
 	return logger
 }
@@ -82,6 +83,16 @@ func RPCLogger() *logrus.Entry {
 	return makeLogger(rpc, logrus.Fields{"layer": "rpc"})
 }
 
+// DAP returns true if dap package should log.
+func DAP() bool {
+	return dap
+}
+
+// DAPLogger returns a logger for dap package.
+func DAPLogger() *logrus.Entry {
+	return makeLogger(dap, logrus.Fields{"layer": "dap"})
+}
+
 // FnCall returns true if the function call protocol should be logged.
 func FnCall() bool {
 	return fnCall
@@ -100,12 +111,21 @@ func MinidumpLogger() *logrus.Entry {
 	return makeLogger(minidump, logrus.Fields{"layer": "core", "kind": "minidump"})
 }
 
+// WriteDAPListeningMessage writes the "DAP server listening" message in dap mode.
+func WriteDAPListeningMessage(addr string) {
+	writeListeningMessage("DAP", addr)
+}
+
 // WriteAPIListeningMessage writes the "API server listening" message in headless mode.
 func WriteAPIListeningMessage(addr string) {
+	writeListeningMessage("API", addr)
+}
+
+func writeListeningMessage(server string, addr string) {
 	if logOut != nil {
-		fmt.Fprintf(logOut, "API server listening at: %s\n", addr)
+		fmt.Fprintf(logOut, "%s server listening at: %s\n", server, addr)
 	} else {
-		fmt.Printf("API server listening at: %s\n", addr)
+		fmt.Printf("%s server listening at: %s\n", server, addr)
 	}
 }
 
@@ -151,10 +171,14 @@ func Setup(logFlag bool, logstr string, logDest string) error {
 			debugLineErrors = true
 		case "rpc":
 			rpc = true
+		case "dap":
+			dap = true
 		case "fncall":
 			fnCall = true
 		case "minidump":
 			minidump = true
+			// If adding another value, do make sure to
+			// update "Help about logging flags" in commands.go.
 		}
 	}
 	return nil
diff --git a/pkg/proc/amd64_arch.go b/pkg/proc/amd64_arch.go
index b6fb445a..31f7e332 100644
--- a/pkg/proc/amd64_arch.go
+++ b/pkg/proc/amd64_arch.go
@@ -1,12 +1,15 @@
 package proc
 
 import (
+	"bytes"
 	"encoding/binary"
+	"fmt"
+	"math"
+	"os"
 	"strings"
 
 	"github.com/go-delve/delve/pkg/dwarf/frame"
 	"github.com/go-delve/delve/pkg/dwarf/op"
-	"golang.org/x/arch/x86/x86asm"
 )
 
 // AMD64 represents the AMD64 CPU architecture.
@@ -216,6 +219,7 @@ func (a *AMD64) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
 			return false
 		}
 
+		it.loadG0SchedSP()
 		if it.g0_sched_sp <= 0 {
 			return false
 		}
@@ -300,24 +304,24 @@ func (a *AMD64) RegSize(regnum uint64) int {
 // figure 3.36
 // https://www.uclibc.org/docs/psABI-x86_64.pdf
 
-var amd64DwarfToHardware = map[int]x86asm.Reg{
-	0:  x86asm.RAX,
-	1:  x86asm.RDX,
-	2:  x86asm.RCX,
-	3:  x86asm.RBX,
-	4:  x86asm.RSI,
-	5:  x86asm.RDI,
-	8:  x86asm.R8,
-	9:  x86asm.R9,
-	10: x86asm.R10,
-	11: x86asm.R11,
-	12: x86asm.R12,
-	13: x86asm.R13,
-	14: x86asm.R14,
-	15: x86asm.R15,
-}
-
 var amd64DwarfToName = map[int]string{
+	0:  "Rax",
+	1:  "Rdx",
+	2:  "Rcx",
+	3:  "Rbx",
+	4:  "Rsi",
+	5:  "Rdi",
+	6:  "Rbp",
+	7:  "Rsp",
+	8:  "R8",
+	9:  "R9",
+	10: "R10",
+	11: "R11",
+	12: "R12",
+	13: "R13",
+	14: "R14",
+	15: "R15",
+	16: "Rip",
 	17: "XMM0",
 	18: "XMM1",
 	19: "XMM2",
@@ -356,13 +360,25 @@ var amd64DwarfToName = map[int]string{
 	66: "SW",
 }
 
+var amd64NameToDwarf = func() map[string]int {
+	r := make(map[string]int)
+	for regNum, regName := range amd64DwarfToName {
+		r[strings.ToLower(regName)] = regNum
+	}
+	r["eflags"] = 49
+	r["st0"] = 33
+	r["st1"] = 34
+	r["st2"] = 35
+	r["st3"] = 36
+	r["st4"] = 37
+	r["st5"] = 38
+	r["st6"] = 39
+	r["st7"] = 40
+	return r
+}()
+
 func maxAmd64DwarfRegister() int {
 	max := int(amd64DwarfIPRegNum)
-	for i := range amd64DwarfToHardware {
-		if i > max {
-			max = i
-		}
-	}
 	for i := range amd64DwarfToName {
 		if i > max {
 			max = i
@@ -376,22 +392,9 @@ func maxAmd64DwarfRegister() int {
 func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
 	dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
 
-	dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
-	dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(regs.SP())
-	dregs[amd64DwarfBPRegNum] = op.DwarfRegisterFromUint64(regs.BP())
-
-	for dwarfReg, asmReg := range amd64DwarfToHardware {
-		v, err := regs.Get(int(asmReg))
-		if err == nil {
-			dregs[dwarfReg] = op.DwarfRegisterFromUint64(v)
-		}
-	}
-
 	for _, reg := range regs.Slice(true) {
-		for dwarfReg, regName := range amd64DwarfToName {
-			if regName == reg.Name {
-				dregs[dwarfReg] = op.DwarfRegisterFromBytes(reg.Bytes)
-			}
+		if dwarfReg, ok := amd64NameToDwarf[strings.ToLower(reg.Name)]; ok {
+			dregs[dwarfReg] = reg.Reg
 		}
 	}
 
@@ -422,3 +425,132 @@ func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
 		BPRegNum:   amd64DwarfBPRegNum,
 	}
 }
+
+func (a *AMD64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string {
+	name = strings.ToLower(name)
+	switch name {
+	case "rflags":
+		return eflagsDescription.Describe(reg.Uint64Val, 64)
+
+	case "cw", "sw", "tw", "fop":
+		return fmt.Sprintf("%#04x", reg.Uint64Val)
+
+	case "mxcsr_mask":
+		return fmt.Sprintf("%#08x", reg.Uint64Val)
+
+	case "mxcsr":
+		return mxcsrDescription.Describe(reg.Uint64Val, 32)
+
+	default:
+		if reg.Bytes != nil && strings.HasPrefix(name, "xmm") {
+			return formatSSEReg(reg.Bytes)
+		} else if reg.Bytes != nil && strings.HasPrefix(name, "st(") {
+			return formatX87Reg(reg.Bytes)
+		} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) <= 8) {
+			return fmt.Sprintf("%#016x", reg.Uint64Val)
+		} else {
+			return fmt.Sprintf("%#x", reg.Bytes)
+		}
+	}
+}
+
+func formatSSEReg(xmm []byte) string {
+	buf := bytes.NewReader(xmm)
+
+	var out bytes.Buffer
+	var vi [16]uint8
+	for i := range vi {
+		binary.Read(buf, binary.LittleEndian, &vi[i])
+	}
+
+	fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
+
+	fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
+
+	fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
+
+	fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
+
+	fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
+
+	buf.Seek(0, os.SEEK_SET)
+	var v2 [2]float64
+	for i := range v2 {
+		binary.Read(buf, binary.LittleEndian, &v2[i])
+	}
+	fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
+
+	buf.Seek(0, os.SEEK_SET)
+	var v4 [4]float32
+	for i := range v4 {
+		binary.Read(buf, binary.LittleEndian, &v4[i])
+	}
+	fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
+
+	return out.String()
+}
+
+func formatX87Reg(b []byte) string {
+	if len(b) < 10 {
+		return fmt.Sprintf("%#x", b)
+	}
+	mantissa := binary.LittleEndian.Uint64(b[:8])
+	exponent := uint16(binary.LittleEndian.Uint16(b[8:]))
+
+	var f float64
+	fset := false
+
+	const (
+		_SIGNBIT    = 1 << 15
+		_EXP_BIAS   = (1 << 14) - 1 // 2^(n-1) - 1 = 16383
+		_SPECIALEXP = (1 << 15) - 1 // all bits set
+		_HIGHBIT    = 1 << 63
+		_QUIETBIT   = 1 << 62
+	)
+
+	sign := 1.0
+	if exponent&_SIGNBIT != 0 {
+		sign = -1.0
+	}
+	exponent &= ^uint16(_SIGNBIT)
+
+	NaN := math.NaN()
+	Inf := math.Inf(+1)
+
+	switch exponent {
+	case 0:
+		switch {
+		case mantissa == 0:
+			f = sign * 0.0
+			fset = true
+		case mantissa&_HIGHBIT != 0:
+			f = NaN
+			fset = true
+		}
+	case _SPECIALEXP:
+		switch {
+		case mantissa&_HIGHBIT == 0:
+			f = sign * Inf
+			fset = true
+		default:
+			f = NaN // signaling NaN
+			fset = true
+		}
+	default:
+		if mantissa&_HIGHBIT == 0 {
+			f = NaN
+			fset = true
+		}
+	}
+
+	if !fset {
+		significand := float64(mantissa) / (1 << 63)
+		f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS))
+	}
+
+	var buf bytes.Buffer
+	binary.Write(&buf, binary.LittleEndian, exponent)
+	binary.Write(&buf, binary.LittleEndian, mantissa)
+
+	return fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)
+}
diff --git a/pkg/proc/arch.go b/pkg/proc/arch.go
index e6490d22..3c27181e 100644
--- a/pkg/proc/arch.go
+++ b/pkg/proc/arch.go
@@ -21,6 +21,7 @@ type Arch interface {
 	RegSize(uint64) int
 	RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
 	AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
+	DwarfRegisterToString(string, *op.DwarfRegister) string
 }
 
 const (
diff --git a/pkg/proc/arm64_arch.go b/pkg/proc/arm64_arch.go
index fad53a86..786e0251 100644
--- a/pkg/proc/arm64_arch.go
+++ b/pkg/proc/arm64_arch.go
@@ -1,7 +1,10 @@
 package proc
 
 import (
+	"bytes"
 	"encoding/binary"
+	"fmt"
+	"os"
 	"strings"
 
 	"github.com/go-delve/delve/pkg/dwarf/frame"
@@ -251,6 +254,7 @@ func (a *ARM64) SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters)
 			return false
 		}
 
+		it.loadG0SchedSP()
 		if it.g0_sched_sp <= 0 {
 			return false
 		}
@@ -406,3 +410,44 @@ func (a *ARM64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
 		LRRegNum:   arm64DwarfLRRegNum,
 	}
 }
+
+func (a *ARM64) DwarfRegisterToString(name string, reg *op.DwarfRegister) string {
+	if reg.Bytes != nil && (name[0] == 'v' || name[0] == 'V') {
+		buf := bytes.NewReader(reg.Bytes)
+
+		var out bytes.Buffer
+		var vi [16]uint8
+		for i := range vi {
+			binary.Read(buf, binary.LittleEndian, &vi[i])
+		}
+
+		fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
+
+		fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
+
+		fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
+
+		fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
+
+		fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
+
+		buf.Seek(0, os.SEEK_SET)
+		var v2 [2]float64
+		for i := range v2 {
+			binary.Read(buf, binary.LittleEndian, &v2[i])
+		}
+		fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
+
+		buf.Seek(0, os.SEEK_SET)
+		var v4 [4]float32
+		for i := range v4 {
+			binary.Read(buf, binary.LittleEndian, &v4[i])
+		}
+		fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
+
+		return out.String()
+	} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) < 16) {
+		return fmt.Sprintf("%#016x", reg.Uint64Val)
+	}
+	return fmt.Sprintf("%#x", reg.Bytes)
+}
diff --git a/pkg/proc/fbsdutil/regs.go b/pkg/proc/fbsdutil/regs.go
index eee30e3f..d00bec95 100644
--- a/pkg/proc/fbsdutil/regs.go
+++ b/pkg/proc/fbsdutil/regs.go
@@ -101,17 +101,17 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
 		// FreeBSD defines the registers as signed, but Linux defines
 		// them as unsigned.  Of course, a register doesn't really have
 		// a concept of signedness.  Cast to what Delve expects.
-		out = proc.AppendQwordReg(out, reg.k, uint64(reg.v))
+		out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
 	}
 	for _, reg := range regs32 {
-		out = proc.AppendDwordReg(out, reg.k, reg.v)
+		out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
 	}
 	for _, reg := range regs16 {
-		out = proc.AppendWordReg(out, reg.k, reg.v)
+		out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
 	}
 	// x86 called this register "Eflags".  amd64 extended it and renamed it
 	// "Rflags", but Linux still uses the old name.
-	out = proc.AppendEflagReg(out, "Rflags", uint64(r.Regs.Rflags))
+	out = proc.AppendUint64Register(out, "Rflags", uint64(r.Regs.Rflags))
 	if floatingPoint {
 		out = append(out, r.Fpregs...)
 	}
diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go
index f73d7691..b4862f14 100644
--- a/pkg/proc/gdbserial/gdbserver.go
+++ b/pkg/proc/gdbserial/gdbserver.go
@@ -518,6 +518,7 @@ func (p *Process) initialize(path string, debugInfoDirs []string) error {
 		p.bi.Close()
 		return err
 	}
+	p.clearThreadSignals()
 
 	if p.conn.pid <= 0 {
 		p.conn.pid, _, err = queryProcessInfo(p, 0)
@@ -663,9 +664,9 @@ continueLoop:
 			return nil, err
 		}
 
-		// For stubs that support qThreadStopInfo updateThreadListNoRegisters will
+		// For stubs that support qThreadStopInfo updateThreadList will
 		// find out the reason why each thread stopped.
-		p.updateThreadListNoRegisters(&tu)
+		p.updateThreadList(&tu)
 
 		trapthread = p.findThreadByStrID(threadID)
 		if trapthread != nil && !p.threadStopInfo {
@@ -681,9 +682,7 @@ continueLoop:
 		}
 	}
 
-	if err := p.updateThreadRegisters(); err != nil {
-		return nil, err
-	}
+	p.clearThreadRegisters()
 
 	if p.BinInfo().GOOS == "linux" {
 		if err := linutil.ElfUpdateSharedObjects(p); err != nil {
@@ -940,6 +939,8 @@ func (p *Process) Restart(pos string) error {
 	if err != nil {
 		return err
 	}
+	p.clearThreadSignals()
+	p.clearThreadRegisters()
 	p.selectedGoroutine, _ = proc.GetG(p.CurrentThread())
 
 	for addr := range p.breakpoints.M {
@@ -1176,13 +1177,12 @@ func (tu *threadUpdater) Finish() {
 	}
 }
 
-// updateThreadListNoRegisters retrieves the list of inferior threads from
+// updateThreadList retrieves the list of inferior threads from
 // the stub and passes it to threadUpdater.
 // Some stubs will return the list of running threads in the stop packet, if
 // this happens the threadUpdater will know that we have already updated the
 // thread list and the first step of updateThreadList will be skipped.
-// Registers are always reloaded.
-func (p *Process) updateThreadListNoRegisters(tu *threadUpdater) error {
+func (p *Process) updateThreadList(tu *threadUpdater) error {
 	if !tu.done {
 		first := true
 		for {
@@ -1222,33 +1222,17 @@ func (p *Process) updateThreadListNoRegisters(tu *threadUpdater) error {
 	return nil
 }
 
-// updateThreadRegisters reloads register informations for all running
-// threads.
-func (p *Process) updateThreadRegisters() error {
+// clearThreadRegisters clears the memoized thread register state.
+func (p *Process) clearThreadRegisters() {
 	for _, thread := range p.threads {
-		if err := thread.reloadRegisters(); err != nil {
-			return err
-		}
+		thread.regs.regs = nil
 	}
-	return nil
 }
 
-// updateThreadsList retrieves the list of inferior threads from the stub
-// and passes it to the threadUpdater.
-// Then it reloads the register information for all running threads.
-// Some stubs will return the list of running threads in the stop packet, if
-// this happens the threadUpdater will know that we have already updated the
-// thread list and the first step of updateThreadList will be skipped.
-// Registers are always reloaded.
-func (p *Process) updateThreadList(tu *threadUpdater) error {
-	err := p.updateThreadListNoRegisters(tu)
-	if err != nil {
-		return err
-	}
+func (p *Process) clearThreadSignals() {
 	for _, th := range p.threads {
 		th.sig = 0
 	}
-	return p.updateThreadRegisters()
 }
 
 func (p *Process) setCurrentBreakpoints() error {
@@ -1312,6 +1296,11 @@ func (t *Thread) ThreadID() int {
 
 // Registers returns the CPU registers for this thread.
 func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) {
+	if t.regs.regs == nil {
+		if err := t.reloadRegisters(); err != nil {
+			return nil, err
+		}
+	}
 	return &t.regs, nil
 }
 
@@ -1345,15 +1334,15 @@ func (t *Thread) stepInstruction(tu *threadUpdater) error {
 		}
 		defer t.p.conn.setBreakpoint(pc)
 	}
+	// Reset thread registers so the next call to
+	// Thread.Registers will not be cached.
+	t.regs.regs = nil
 	return t.p.conn.step(t.strID, tu, false)
 }
 
 // StepInstruction will step exactly 1 CPU instruction.
 func (t *Thread) StepInstruction() error {
-	if err := t.stepInstruction(&threadUpdater{p: t.p}); err != nil {
-		return err
-	}
-	return t.reloadRegisters()
+	return t.stepInstruction(&threadUpdater{p: t.p})
 }
 
 // Blocked returns true if the thread is blocked in runtime or kernel code.
@@ -1903,15 +1892,15 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
 		}
 		switch {
 		case reginfo.Name == "eflags":
-			r = proc.AppendEflagReg(r, reginfo.Name, uint64(binary.LittleEndian.Uint32(regs.regs[reginfo.Name].value)))
+			r = proc.AppendBytesRegister(r, "Rflags", regs.regs[reginfo.Name].value)
 		case reginfo.Name == "mxcsr":
-			r = proc.AppendMxcsrReg(r, reginfo.Name, uint64(binary.LittleEndian.Uint32(regs.regs[reginfo.Name].value)))
+			r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
 		case reginfo.Bitsize == 16:
-			r = proc.AppendWordReg(r, reginfo.Name, binary.LittleEndian.Uint16(regs.regs[reginfo.Name].value))
+			r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
 		case reginfo.Bitsize == 32:
-			r = proc.AppendDwordReg(r, reginfo.Name, binary.LittleEndian.Uint32(regs.regs[reginfo.Name].value))
+			r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
 		case reginfo.Bitsize == 64:
-			r = proc.AppendQwordReg(r, reginfo.Name, binary.LittleEndian.Uint64(regs.regs[reginfo.Name].value))
+			r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value)
 		case reginfo.Bitsize == 80:
 			if !floatingPoint {
 				continue
@@ -1923,12 +1912,11 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
 					break
 				}
 			}
-			value := regs.regs[reginfo.Name].value
-			r = proc.AppendX87Reg(r, idx, binary.LittleEndian.Uint16(value[8:]), binary.LittleEndian.Uint64(value[:8]))
+			r = proc.AppendBytesRegister(r, fmt.Sprintf("ST(%d)", idx), regs.regs[reginfo.Name].value)
 
 		case reginfo.Bitsize == 128:
 			if floatingPoint {
-				r = proc.AppendSSEReg(r, strings.ToUpper(reginfo.Name), regs.regs[reginfo.Name].value)
+				r = proc.AppendBytesRegister(r, strings.ToUpper(reginfo.Name), regs.regs[reginfo.Name].value)
 			}
 
 		case reginfo.Bitsize == 256:
@@ -1938,8 +1926,8 @@ func (regs *gdbRegisters) Slice(floatingPoint bool) []proc.Register {
 
 			value := regs.regs[reginfo.Name].value
 			xmmName := "x" + reginfo.Name[1:]
-			r = proc.AppendSSEReg(r, strings.ToUpper(xmmName), value[:16])
-			r = proc.AppendSSEReg(r, strings.ToUpper(reginfo.Name), value[16:])
+			r = proc.AppendBytesRegister(r, strings.ToUpper(xmmName), value[:16])
+			r = proc.AppendBytesRegister(r, strings.ToUpper(reginfo.Name), value[16:])
 		}
 	}
 	return r
diff --git a/pkg/proc/linutil/regs_amd64_arch.go b/pkg/proc/linutil/regs_amd64_arch.go
index 1a708d1c..be1781bf 100644
--- a/pkg/proc/linutil/regs_amd64_arch.go
+++ b/pkg/proc/linutil/regs_amd64_arch.go
@@ -75,7 +75,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
 		{"R15", r.Regs.R15},
 		{"Orig_rax", r.Regs.Orig_rax},
 		{"Cs", r.Regs.Cs},
-		{"Eflags", r.Regs.Eflags},
+		{"Rflags", r.Regs.Eflags},
 		{"Ss", r.Regs.Ss},
 		{"Fs_base", r.Regs.Fs_base},
 		{"Gs_base", r.Regs.Gs_base},
@@ -86,11 +86,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
 	}
 	out := make([]proc.Register, 0, len(regs)+len(r.Fpregs))
 	for _, reg := range regs {
-		if reg.k == "Eflags" {
-			out = proc.AppendEflagReg(out, reg.k, reg.v)
-		} else {
-			out = proc.AppendQwordReg(out, reg.k, reg.v)
-		}
+		out = proc.AppendUint64Register(out, reg.k, reg.v)
 	}
 	if floatingPoint {
 		out = append(out, r.Fpregs...)
@@ -325,25 +321,28 @@ type AMD64Xstate struct {
 // Decode decodes an XSAVE area to a list of name/value pairs of registers.
 func (xsave *AMD64Xstate) Decode() (regs []proc.Register) {
 	// x87 registers
-	regs = proc.AppendWordReg(regs, "CW", xsave.Cwd)
-	regs = proc.AppendWordReg(regs, "SW", xsave.Swd)
-	regs = proc.AppendWordReg(regs, "TW", xsave.Ftw)
-	regs = proc.AppendWordReg(regs, "FOP", xsave.Fop)
-	regs = proc.AppendQwordReg(regs, "FIP", xsave.Rip)
-	regs = proc.AppendQwordReg(regs, "FDP", xsave.Rdp)
+	regs = proc.AppendUint64Register(regs, "CW", uint64(xsave.Cwd))
+	regs = proc.AppendUint64Register(regs, "SW", uint64(xsave.Swd))
+	regs = proc.AppendUint64Register(regs, "TW", uint64(xsave.Ftw))
+	regs = proc.AppendUint64Register(regs, "FOP", uint64(xsave.Fop))
+	regs = proc.AppendUint64Register(regs, "FIP", xsave.Rip)
+	regs = proc.AppendUint64Register(regs, "FDP", xsave.Rdp)
 
 	for i := 0; i < len(xsave.StSpace); i += 4 {
-		regs = proc.AppendX87Reg(regs, i/4, uint16(xsave.StSpace[i+2]), uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
+		var buf bytes.Buffer
+		binary.Write(&buf, binary.LittleEndian, uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
+		binary.Write(&buf, binary.LittleEndian, uint16(xsave.StSpace[i+2]))
+		regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ST(%d)", i/4), buf.Bytes())
 	}
 
 	// SSE registers
-	regs = proc.AppendMxcsrReg(regs, "MXCSR", uint64(xsave.Mxcsr))
-	regs = proc.AppendDwordReg(regs, "MXCSR_MASK", xsave.MxcrMask)
+	regs = proc.AppendUint64Register(regs, "MXCSR", uint64(xsave.Mxcsr))
+	regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xsave.MxcrMask))
 
 	for i := 0; i < len(xsave.XmmSpace); i += 16 {
-		regs = proc.AppendSSEReg(regs, fmt.Sprintf("XMM%d", i/16), xsave.XmmSpace[i:i+16])
+		regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", i/16), xsave.XmmSpace[i:i+16])
 		if xsave.AvxState {
-			regs = proc.AppendSSEReg(regs, fmt.Sprintf("YMM%d", i/16), xsave.YmmSpace[i:i+16])
+			regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", i/16), xsave.YmmSpace[i:i+16])
 		}
 	}
 
diff --git a/pkg/proc/linutil/regs_arm64_arch.go b/pkg/proc/linutil/regs_arm64_arch.go
index 6a06f8dc..4373822d 100644
--- a/pkg/proc/linutil/regs_arm64_arch.go
+++ b/pkg/proc/linutil/regs_arm64_arch.go
@@ -67,7 +67,7 @@ func (r *ARM64Registers) Slice(floatingPoint bool) []proc.Register {
 	}
 	out := make([]proc.Register, 0, len(regs64)+len(r.Fpregs))
 	for _, reg := range regs64 {
-		out = proc.AppendQwordReg(out, reg.k, reg.v)
+		out = proc.AppendUint64Register(out, reg.k, reg.v)
 	}
 	out = append(out, r.Fpregs...)
 	return out
@@ -128,7 +128,7 @@ func (r *ARM64Registers) Copy() proc.Registers {
 // Decode decodes an XSAVE area to a list of name/value pairs of registers.
 func Decode(fpregs []byte) (regs []proc.Register) {
 	for i := 0; i < len(fpregs); i += 16 {
-		regs = proc.AppendFPReg(regs, fmt.Sprintf("V%d", i/16), fpregs[i:i+16])
+		regs = proc.AppendBytesRegister(regs, fmt.Sprintf("V%d", i/16), fpregs[i:i+16])
 	}
 	return
 }
diff --git a/pkg/proc/native/registers_darwin_amd64.go b/pkg/proc/native/registers_darwin_amd64.go
index 86bfba20..070eb4df 100644
--- a/pkg/proc/native/registers_darwin_amd64.go
+++ b/pkg/proc/native/registers_darwin_amd64.go
@@ -5,7 +5,6 @@ package native
 // #include "threads_darwin.h"
 import "C"
 import (
-	"encoding/binary"
 	"errors"
 	"fmt"
 	"unsafe"
@@ -73,9 +72,9 @@ func (r *Regs) Slice(floatingPoint bool) []proc.Register {
 	out := make([]proc.Register, 0, len(regs)+len(r.fpregs))
 	for _, reg := range regs {
 		if reg.k == "Rflags" {
-			out = proc.AppendEflagReg(out, reg.k, reg.v)
+			out = proc.AppendUint64Register(out, reg.k, reg.v)
 		} else {
-			out = proc.AppendQwordReg(out, reg.k, reg.v)
+			out = proc.AppendUint64Register(out, reg.k, reg.v)
 		}
 	}
 	if floatingPoint {
@@ -342,25 +341,23 @@ func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
 			return nil, fmt.Errorf("could not get floating point registers")
 		}
 
-		regs.fpregs = proc.AppendWordReg(regs.fpregs, "CW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw))))
-		regs.fpregs = proc.AppendWordReg(regs.fpregs, "SW", *((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw))))
-		regs.fpregs = proc.AppendWordReg(regs.fpregs, "TW", uint16(fpstate.__fpu_ftw))
-		regs.fpregs = proc.AppendWordReg(regs.fpregs, "FOP", uint16(fpstate.__fpu_fop))
-		regs.fpregs = proc.AppendQwordReg(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
-		regs.fpregs = proc.AppendQwordReg(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "CW", uint64(*((*uint16)(unsafe.Pointer(&fpstate.__fpu_fcw)))))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "SW", uint64(*((*uint16)(unsafe.Pointer(&fpstate.__fpu_fsw)))))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "TW", uint64(fpstate.__fpu_ftw))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FOP", uint64(fpstate.__fpu_fop))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FIP", uint64(fpstate.__fpu_cs)<<32|uint64(fpstate.__fpu_ip))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "FDP", uint64(fpstate.__fpu_ds)<<32|uint64(fpstate.__fpu_dp))
 
 		for i, st := range []*C.char{&fpstate.__fpu_stmm0.__mmst_reg[0], &fpstate.__fpu_stmm1.__mmst_reg[0], &fpstate.__fpu_stmm2.__mmst_reg[0], &fpstate.__fpu_stmm3.__mmst_reg[0], &fpstate.__fpu_stmm4.__mmst_reg[0], &fpstate.__fpu_stmm5.__mmst_reg[0], &fpstate.__fpu_stmm6.__mmst_reg[0], &fpstate.__fpu_stmm7.__mmst_reg[0]} {
 			stb := C.GoBytes(unsafe.Pointer(st), 10)
-			mantissa := binary.LittleEndian.Uint64(stb[:8])
-			exponent := binary.LittleEndian.Uint16(stb[8:])
-			regs.fpregs = proc.AppendX87Reg(regs.fpregs, i, exponent, mantissa)
+			regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("ST(%d)", i), stb)
 		}
 
-		regs.fpregs = proc.AppendMxcsrReg(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr))
-		regs.fpregs = proc.AppendDwordReg(regs.fpregs, "MXCSR_MASK", uint32(fpstate.__fpu_mxcsrmask))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "MXCSR", uint64(fpstate.__fpu_mxcsr))
+		regs.fpregs = proc.AppendUint64Register(regs.fpregs, "MXCSR_MASK", uint64(fpstate.__fpu_mxcsrmask))
 
 		for i, xmm := range []*C.char{&fpstate.__fpu_xmm0.__xmm_reg[0], &fpstate.__fpu_xmm1.__xmm_reg[0], &fpstate.__fpu_xmm2.__xmm_reg[0], &fpstate.__fpu_xmm3.__xmm_reg[0], &fpstate.__fpu_xmm4.__xmm_reg[0], &fpstate.__fpu_xmm5.__xmm_reg[0], &fpstate.__fpu_xmm6.__xmm_reg[0], &fpstate.__fpu_xmm7.__xmm_reg[0], &fpstate.__fpu_xmm8.__xmm_reg[0], &fpstate.__fpu_xmm9.__xmm_reg[0], &fpstate.__fpu_xmm10.__xmm_reg[0], &fpstate.__fpu_xmm11.__xmm_reg[0], &fpstate.__fpu_xmm12.__xmm_reg[0], &fpstate.__fpu_xmm13.__xmm_reg[0], &fpstate.__fpu_xmm14.__xmm_reg[0], &fpstate.__fpu_xmm15.__xmm_reg[0]} {
-			regs.fpregs = proc.AppendSSEReg(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
+			regs.fpregs = proc.AppendBytesRegister(regs.fpregs, fmt.Sprintf("XMM%d", i), C.GoBytes(unsafe.Pointer(xmm), 16))
 		}
 	}
 	return regs, nil
diff --git a/pkg/proc/registers.go b/pkg/proc/registers.go
index 2d884238..1bce1b19 100644
--- a/pkg/proc/registers.go
+++ b/pkg/proc/registers.go
@@ -1,13 +1,12 @@
 package proc
 
 import (
-	"bytes"
-	"encoding/binary"
 	"errors"
 	"fmt"
 	"math"
-	"os"
 	"strings"
+
+	"github.com/go-delve/delve/pkg/dwarf/op"
 )
 
 // Registers is an interface for a generic register type. The
@@ -30,180 +29,16 @@ type Registers interface {
 
 // Register represents a CPU register.
 type Register struct {
-	Name  string
-	Bytes []byte
-	Value string
-}
-
-// AppendWordReg appends a word (16 bit) register to regs.
-func AppendWordReg(regs []Register, name string, value uint16) []Register {
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.LittleEndian, value)
-	return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#04x", value)})
-}
-
-// AppendDwordReg appends a double word (32 bit) register to regs.
-func AppendDwordReg(regs []Register, name string, value uint32) []Register {
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.LittleEndian, value)
-	return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#08x", value)})
-}
-
-// AppendQwordReg appends a quad word (64 bit) register to regs.
-func AppendQwordReg(regs []Register, name string, value uint64) []Register {
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.LittleEndian, value)
-	return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#016x", value)})
-}
-
-func appendFlagReg(regs []Register, name string, value uint64, descr flagRegisterDescr, size int) []Register {
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.LittleEndian, value)
-	return append(regs, Register{name, buf.Bytes()[:size], descr.Describe(value, size)})
-}
-
-// AppendEflagReg appends EFLAG register to regs.
-func AppendEflagReg(regs []Register, name string, value uint64) []Register {
-	return appendFlagReg(regs, name, value, eflagsDescription, 64)
-}
-
-// AppendMxcsrReg appends MXCSR register to regs.
-func AppendMxcsrReg(regs []Register, name string, value uint64) []Register {
-	return appendFlagReg(regs, name, value, mxcsrDescription, 32)
-}
-
-// AppendX87Reg appends a 80 bit float register to regs.
-func AppendX87Reg(regs []Register, index int, exponent uint16, mantissa uint64) []Register {
-	var f float64
-	fset := false
-
-	const (
-		_SIGNBIT    = 1 << 15
-		_EXP_BIAS   = (1 << 14) - 1 // 2^(n-1) - 1 = 16383
-		_SPECIALEXP = (1 << 15) - 1 // all bits set
-		_HIGHBIT    = 1 << 63
-		_QUIETBIT   = 1 << 62
-	)
-
-	sign := 1.0
-	if exponent&_SIGNBIT != 0 {
-		sign = -1.0
-	}
-	exponent &= ^uint16(_SIGNBIT)
-
-	NaN := math.NaN()
-	Inf := math.Inf(+1)
-
-	switch exponent {
-	case 0:
-		switch {
-		case mantissa == 0:
-			f = sign * 0.0
-			fset = true
-		case mantissa&_HIGHBIT != 0:
-			f = NaN
-			fset = true
-		}
-	case _SPECIALEXP:
-		switch {
-		case mantissa&_HIGHBIT == 0:
-			f = sign * Inf
-			fset = true
-		default:
-			f = NaN // signaling NaN
-			fset = true
-		}
-	default:
-		if mantissa&_HIGHBIT == 0 {
-			f = NaN
-			fset = true
-		}
-	}
-
-	if !fset {
-		significand := float64(mantissa) / (1 << 63)
-		f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS))
-	}
-
-	var buf bytes.Buffer
-	binary.Write(&buf, binary.LittleEndian, exponent)
-	binary.Write(&buf, binary.LittleEndian, mantissa)
-
-	return append(regs, Register{fmt.Sprintf("ST(%d)", index), buf.Bytes(), fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)})
+	Name string
+	Reg  *op.DwarfRegister
 }
 
-// AppendSSEReg appends a 256 bit SSE register to regs.
-func AppendSSEReg(regs []Register, name string, xmm []byte) []Register {
-	buf := bytes.NewReader(xmm)
-
-	var out bytes.Buffer
-	var vi [16]uint8
-	for i := range vi {
-		binary.Read(buf, binary.LittleEndian, &vi[i])
-	}
-
-	fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
-
-	fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
-
-	fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
-
-	fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
-
-	fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
-
-	buf.Seek(0, os.SEEK_SET)
-	var v2 [2]float64
-	for i := range v2 {
-		binary.Read(buf, binary.LittleEndian, &v2[i])
-	}
-	fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
-
-	buf.Seek(0, os.SEEK_SET)
-	var v4 [4]float32
-	for i := range v4 {
-		binary.Read(buf, binary.LittleEndian, &v4[i])
-	}
-	fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
-
-	return append(regs, Register{name, xmm, out.String()})
+func AppendUint64Register(regs []Register, name string, value uint64) []Register {
+	return append(regs, Register{name, op.DwarfRegisterFromUint64(value)})
 }
 
-// AppendFPReg appends a 128 bit FP register to regs.
-func AppendFPReg(regs []Register, name string, reg_value []byte) []Register {
-	buf := bytes.NewReader(reg_value)
-
-	var out bytes.Buffer
-	var vi [16]uint8
-	for i := range vi {
-		binary.Read(buf, binary.LittleEndian, &vi[i])
-	}
-
-	fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
-
-	fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
-
-	fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
-
-	fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
-
-	fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
-
-	buf.Seek(0, os.SEEK_SET)
-	var v2 [2]float64
-	for i := range v2 {
-		binary.Read(buf, binary.LittleEndian, &v2[i])
-	}
-	fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
-
-	buf.Seek(0, os.SEEK_SET)
-	var v4 [4]float32
-	for i := range v4 {
-		binary.Read(buf, binary.LittleEndian, &v4[i])
-	}
-	fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
-
-	return append(regs, Register{name, reg_value, out.String()})
+func AppendBytesRegister(regs []Register, name string, value []byte) []Register {
+	return append(regs, Register{name, op.DwarfRegisterFromBytes(value)})
 }
 
 // ErrUnknownRegister is returned when the value of an unknown
diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go
index 9f87d93b..2cfcc6ae 100644
--- a/pkg/proc/stack.go
+++ b/pkg/proc/stack.go
@@ -190,8 +190,9 @@ type stackIterator struct {
 	// regs is the register set for the current frame
 	regs op.DwarfRegisters
 
-	g           *G     // the goroutine being stacktraced, nil if we are stacktracing a goroutine-less thread
-	g0_sched_sp uint64 // value of g0.sched.sp (see comments around its use)
+	g                  *G     // the goroutine being stacktraced, nil if we are stacktracing a goroutine-less thread
+	g0_sched_sp        uint64 // value of g0.sched.sp (see comments around its use)
+	g0_sched_sp_loaded bool   // g0_sched_sp was loaded from g0
 
 	opts StacktraceOptions
 }
@@ -221,19 +222,11 @@ func newStackIterator(bi *BinaryInfo, mem MemoryReadWriter, regs op.DwarfRegiste
 		}
 		stkbar = stkbar[stkbarPos:]
 	}
-	var g0_sched_sp uint64
 	systemstack := true
 	if g != nil {
 		systemstack = g.SystemStack
-		g0var, _ := g.variable.fieldVariable("m").structMember("g0")
-		if g0var != nil {
-			g0, _ := g0var.parseG()
-			if g0 != nil {
-				g0_sched_sp = g0.SP
-			}
-		}
 	}
-	return &stackIterator{pc: regs.PC(), regs: regs, top: true, bi: bi, mem: mem, err: nil, atend: false, stackhi: stackhi, stackBarrierPC: stackBarrierPC, stkbar: stkbar, systemstack: systemstack, g: g, g0_sched_sp: g0_sched_sp, opts: opts}
+	return &stackIterator{pc: regs.PC(), regs: regs, top: true, bi: bi, mem: mem, err: nil, atend: false, stackhi: stackhi, stackBarrierPC: stackBarrierPC, stkbar: stkbar, systemstack: systemstack, g: g, opts: opts}
 }
 
 // Next points the iterator to the next stack frame.
@@ -535,6 +528,22 @@ func (it *stackIterator) readRegisterAt(regnum uint64, addr uint64) (*op.DwarfRe
 	return op.DwarfRegisterFromBytes(buf), nil
 }
 
+func (it *stackIterator) loadG0SchedSP() {
+	if it.g0_sched_sp_loaded {
+		return
+	}
+	it.g0_sched_sp_loaded = true
+	if it.g != nil {
+		g0var, _ := it.g.variable.fieldVariable("m").structMember("g0")
+		if g0var != nil {
+			g0, _ := g0var.parseG()
+			if g0 != nil {
+				it.g0_sched_sp = g0.SP
+			}
+		}
+	}
+}
+
 // Defer represents one deferred call
 type Defer struct {
 	DeferredPC uint64 // Value of field _defer.fn.fn, the deferred function
diff --git a/pkg/proc/winutil/regs.go b/pkg/proc/winutil/regs.go
index 46731e96..6ea2baa2 100644
--- a/pkg/proc/winutil/regs.go
+++ b/pkg/proc/winutil/regs.go
@@ -1,6 +1,8 @@
 package winutil
 
 import (
+	"bytes"
+	"encoding/binary"
 	"fmt"
 	"unsafe"
 
@@ -96,7 +98,7 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
 		{"R13", r.r13},
 		{"R14", r.r14},
 		{"R15", r.r15},
-		{"Eflags", r.eflags},
+		{"Rflags", r.eflags},
 		{"Cs", r.cs},
 		{"Fs", r.fs},
 		{"Gs", r.gs},
@@ -108,29 +110,28 @@ func (r *AMD64Registers) Slice(floatingPoint bool) []proc.Register {
 	}
 	out := make([]proc.Register, 0, outlen)
 	for _, reg := range regs {
-		if reg.k == "Eflags" {
-			out = proc.AppendEflagReg(out, reg.k, reg.v)
-		} else {
-			out = proc.AppendQwordReg(out, reg.k, reg.v)
-		}
+		out = proc.AppendUint64Register(out, reg.k, reg.v)
 	}
 	if r.fltSave != nil && floatingPoint {
-		out = proc.AppendWordReg(out, "CW", r.fltSave.ControlWord)
-		out = proc.AppendWordReg(out, "SW", r.fltSave.StatusWord)
-		out = proc.AppendWordReg(out, "TW", uint16(r.fltSave.TagWord))
-		out = proc.AppendWordReg(out, "FOP", r.fltSave.ErrorOpcode)
-		out = proc.AppendQwordReg(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset))
-		out = proc.AppendQwordReg(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset))
+		out = proc.AppendUint64Register(out, "CW", uint64(r.fltSave.ControlWord))
+		out = proc.AppendUint64Register(out, "SW", uint64(r.fltSave.StatusWord))
+		out = proc.AppendUint64Register(out, "TW", uint64(uint16(r.fltSave.TagWord)))
+		out = proc.AppendUint64Register(out, "FOP", uint64(r.fltSave.ErrorOpcode))
+		out = proc.AppendUint64Register(out, "FIP", uint64(r.fltSave.ErrorSelector)<<32|uint64(r.fltSave.ErrorOffset))
+		out = proc.AppendUint64Register(out, "FDP", uint64(r.fltSave.DataSelector)<<32|uint64(r.fltSave.DataOffset))
 
 		for i := range r.fltSave.FloatRegisters {
-			out = proc.AppendX87Reg(out, i, uint16(r.fltSave.FloatRegisters[i].High), r.fltSave.FloatRegisters[i].Low)
+			var buf bytes.Buffer
+			binary.Write(&buf, binary.LittleEndian, r.fltSave.FloatRegisters[i].Low)
+			binary.Write(&buf, binary.LittleEndian, r.fltSave.FloatRegisters[i].High)
+			out = proc.AppendBytesRegister(out, fmt.Sprintf("ST(%d)", i), buf.Bytes())
 		}
 
-		out = proc.AppendMxcsrReg(out, "MXCSR", uint64(r.fltSave.MxCsr))
-		out = proc.AppendDwordReg(out, "MXCSR_MASK", r.fltSave.MxCsr_Mask)
+		out = proc.AppendUint64Register(out, "MXCSR", uint64(r.fltSave.MxCsr))
+		out = proc.AppendUint64Register(out, "MXCSR_MASK", uint64(r.fltSave.MxCsr_Mask))
 
 		for i := 0; i < len(r.fltSave.XmmRegisters); i += 16 {
-			out = proc.AppendSSEReg(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16])
+			out = proc.AppendBytesRegister(out, fmt.Sprintf("XMM%d", i/16), r.fltSave.XmmRegisters[i:i+16])
 		}
 	}
 	return out
diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go
index f01eb7ef..ad4ffd5d 100644
--- a/pkg/terminal/command.go
+++ b/pkg/terminal/command.go
@@ -7,6 +7,10 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
+	"github.com/cosiner/argv"
+	"github.com/go-delve/delve/service"
+	"github.com/go-delve/delve/service/api"
+	"github.com/go-delve/delve/service/debugger"
 	"go/parser"
 	"go/scanner"
 	"io"
@@ -20,11 +24,6 @@ import (
 	"strconv"
 	"strings"
 	"text/tabwriter"
-
-	"github.com/cosiner/argv"
-	"github.com/go-delve/delve/service"
-	"github.com/go-delve/delve/service/api"
-	"github.com/go-delve/delve/service/debugger"
 )
 
 const optimizedFunctionWarning = "Warning: debugging optimized function"
@@ -368,6 +367,15 @@ Defines <alias> as an alias to <command> or removes an alias.`},
 	
 If locspec is omitted edit will open the current source file in the editor, otherwise it will open the specified location.`},
 		{aliases: []string{"libraries"}, cmdFn: libraries, helpMsg: `List loaded dynamic libraries`},
+
+		{aliases: []string{"examinemem", "x"}, cmdFn: examineMemoryCmd, helpMsg: `Examine memory:
+
+    examinemem [-fmt <format>] [-len <length>] <address>
+
+Format represents the data format and the value is one of this list (default hex): oct(octal), hex(hexadecimal), dec(decimal), bin(binary).
+Length is the number of bytes (default 1) and must be less than or equal to 1000.
+Address is the memory location of the target to examine.
+For example:  x -fmt hex -len 20 0xc00008af38`},
 	}
 
 	if client == nil || client.Recorded() {
@@ -1349,6 +1357,81 @@ func edit(t *Term, ctx callContext, args string) error {
 	return cmd.Run()
 }
 
+func examineMemoryCmd(t *Term, ctx callContext, args string) error {
+	v := strings.FieldsFunc(args, func(c rune) bool {
+		return c == ' '
+	})
+
+	var (
+		address int64
+		err     error
+		ok      bool
+	)
+
+	// Default value
+	priFmt := byte('x')
+	length := 1
+
+	for i := 0; i < len(v); i++ {
+		switch v[i] {
+		case "-fmt":
+			i++
+			if i >= len(v) {
+				return fmt.Errorf("expected argument after -fmt")
+			}
+			fmtMapToPriFmt := map[string]byte{
+				"oct":         'o',
+				"octal":       'o',
+				"hex":         'x',
+				"hexadecimal": 'x',
+				"dec":         'd',
+				"decimal":     'd',
+				"bin":         'b',
+				"binary":      'b',
+			}
+			priFmt, ok = fmtMapToPriFmt[v[i]]
+			if !ok {
+				return fmt.Errorf("%q is not a valid format", v[i])
+			}
+		case "-len":
+			i++
+			if i >= len(v) {
+				return fmt.Errorf("expected argument after -len")
+			}
+			var err error
+			length, err = strconv.Atoi(v[i])
+			if err != nil || length <= 0 {
+				return fmt.Errorf("len must be an positive integer")
+			}
+			// TODO, maybe configured by user.
+			if length > 1000 {
+				return fmt.Errorf("len must be less than or equal to 1000")
+			}
+		default:
+			if i != len(v)-1 {
+				return fmt.Errorf("unknown option %q", v[i])
+			}
+			// TODO, maybe we can support expression.
+			address, err = strconv.ParseInt(v[len(v)-1], 0, 64)
+			if err != nil {
+				return fmt.Errorf("convert address into uintptr type failed, %s", err)
+			}
+		}
+	}
+
+	if address == 0 {
+		return fmt.Errorf("no address specified")
+	}
+
+	memArea, err := t.client.ExamineMemory(uintptr(address), length)
+	if err != nil {
+		return err
+	}
+
+	fmt.Println(api.PrettyExamineMemory(uintptr(address), memArea, priFmt))
+	return nil
+}
+
 func printVar(t *Term, ctx callContext, args string) error {
 	if len(args) == 0 {
 		return fmt.Errorf("not enough arguments")
diff --git a/pkg/terminal/docgen.go b/pkg/terminal/docgen.go
index f04d7d76..04972186 100644
--- a/pkg/terminal/docgen.go
+++ b/pkg/terminal/docgen.go
@@ -27,12 +27,11 @@ func replaceDocPath(s string) string {
 }
 
 func (commands *Commands) WriteMarkdown(w io.Writer) {
-	fmt.Fprint(w, "# Configuration\n\n")
-	fmt.Fprint(w, "Delve can be configured via the configuration file located in `$HOME/.config/dlv/config.yml`.\n")
-	fmt.Fprint(w, "You can open the file and discover all the configurable options and their default value.\n\n")
-
-	fmt.Fprint(w, "# History\n\n")
-	fmt.Fprint(w, "The command history of delve debugger is stored in `$HOME/.config/dlv/.dbg_history`.\n\n")
+	fmt.Fprint(w, "# Configuration and Command History\n\n")
+	fmt.Fprint(w, "If `$XDG_CONFIG_HOME` is set, then configuration and command history files are located in `$XDG_CONFIG_HOME/dlv`. ")
+	fmt.Fprint(w, "Otherwise, they are located in `$HOME/.config/dlv` on Linux and `$HOME/.dlv` on other systems.\n\n")
+	fmt.Fprint(w, "The configuration file `config.yml` contains all the configurable options and their default values. ")
+	fmt.Fprint(w, "The command history is stored in `.dbg_history`.\n\n")
 
 	fmt.Fprint(w, "# Commands\n\n")
 
diff --git a/pkg/terminal/starbind/starlark_mapping.go b/pkg/terminal/starbind/starlark_mapping.go
index f00059a4..4bf55bbe 100644
--- a/pkg/terminal/starbind/starlark_mapping.go
+++ b/pkg/terminal/starbind/starlark_mapping.go
@@ -450,6 +450,44 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
 		}
 		return env.interfaceToStarlarkValue(rpcRet), nil
 	})
+	r["examine_memory"] = starlark.NewBuiltin("examine_memory", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
+		if err := isCancelled(thread); err != nil {
+			return starlark.None, decorateError(thread, err)
+		}
+		var rpcArgs rpc2.ExamineMemoryIn
+		var rpcRet rpc2.ExaminedMemoryOut
+		if len(args) > 0 && args[0] != starlark.None {
+			err := unmarshalStarlarkValue(args[0], &rpcArgs.Address, "Address")
+			if err != nil {
+				return starlark.None, decorateError(thread, err)
+			}
+		}
+		if len(args) > 1 && args[1] != starlark.None {
+			err := unmarshalStarlarkValue(args[1], &rpcArgs.Length, "Length")
+			if err != nil {
+				return starlark.None, decorateError(thread, err)
+			}
+		}
+		for _, kv := range kwargs {
+			var err error
+			switch kv[0].(starlark.String) {
+			case "Address":
+				err = unmarshalStarlarkValue(kv[1], &rpcArgs.Address, "Address")
+			case "Length":
+				err = unmarshalStarlarkValue(kv[1], &rpcArgs.Length, "Length")
+			default:
+				err = fmt.Errorf("unknown argument %q", kv[0])
+			}
+			if err != nil {
+				return starlark.None, decorateError(thread, err)
+			}
+		}
+		err := env.ctx.Client().CallAPI("ExamineMemory", &rpcArgs, &rpcRet)
+		if err != nil {
+			return starlark.None, err
+		}
+		return env.interfaceToStarlarkValue(rpcRet), nil
+	})
 	r["find_location"] = starlark.NewBuiltin("find_location", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
 		if err := isCancelled(thread); err != nil {
 			return starlark.None, decorateError(thread, err)
diff --git a/service/api/conversions.go b/service/api/conversions.go
index b7dfc1ae..3cf1bd97 100644
--- a/service/api/conversions.go
+++ b/service/api/conversions.go
@@ -328,10 +328,10 @@ func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
 }
 
 // ConvertRegisters converts proc.Register to api.Register for a slice.
-func ConvertRegisters(in []proc.Register) (out []Register) {
+func ConvertRegisters(in []proc.Register, arch proc.Arch) (out []Register) {
 	out = make([]Register, len(in))
 	for i := range in {
-		out[i] = Register{in[i].Name, in[i].Value}
+		out[i] = Register{in[i].Name, arch.DwarfRegisterToString(in[i].Name, in[i].Reg)}
 	}
 	return
 }
diff --git a/service/api/prettyprint.go b/service/api/prettyprint.go
index 5100bf8f..b62e37a8 100644
--- a/service/api/prettyprint.go
+++ b/service/api/prettyprint.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"io"
 	"reflect"
+	"strconv"
 	"strings"
 )
 
@@ -354,3 +355,53 @@ func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent stri
 
 	fmt.Fprint(buf, "]")
 }
+
+func PrettyExamineMemory(address uintptr, memArea []byte, format byte) string {
+	cols := 8
+	// Avoid emitting rows that are too long when using binary format
+	if format == 'b' {
+		cols = 4
+	}
+
+	l := len(memArea)
+	rows := l / cols
+	if l%cols != 0 {
+		rows++
+	}
+
+	var colFormat string
+	// Leading zero and occupy 8 for binary
+	if format == 'b' {
+		colFormat = "    %#08b"
+	} else {
+		var maxColCharNum int
+		for i := 0; i < rows; i++ {
+			for j := 0; j < cols && i*cols+j < l; j++ {
+				curColCharNum := len(fmt.Sprintf("%#"+string(format), memArea[i*cols+j]))
+				if curColCharNum > maxColCharNum {
+					maxColCharNum = curColCharNum
+				}
+			}
+		}
+		colFormat = "    %#-" + strconv.Itoa(maxColCharNum) + string(format)
+	}
+
+	lines := ""
+	for i := 0; i < rows; i++ {
+		lines += fmt.Sprintf("%#x:", address)
+		for j := 0; j < cols && i*cols+j < l; j++ {
+			curOutput := fmt.Sprintf(colFormat, memArea[i*cols+j])
+
+			// Diffrent versions of golang output differently if binary.
+			// See https://ci.appveyor.com/project/derekparker/delve-facy3/builds/30179356.
+			// Remove prefix `0b` if binary in some versions of golang because it is not graceful.
+			if format == 'b' && strings.Contains(curOutput, "0b") {
+				curOutput = "    " + curOutput[6:]
+			}
+			lines += curOutput
+		}
+		lines += "\n"
+		address += uintptr(cols)
+	}
+	return lines
+}
diff --git a/service/client.go b/service/client.go
index 6b617cd7..5544091a 100644
--- a/service/client.go
+++ b/service/client.go
@@ -147,6 +147,11 @@ type Client interface {
 	// ListDynamicLibraries returns a list of loaded dynamic libraries.
 	ListDynamicLibraries() ([]api.Image, error)
 
+	// ExamineMemory returns the raw memory stored at the given address.
+	// The amount of data to be read is specified by length which must be less than or equal to 1000.
+	// This function will return an error if it reads less than `length` bytes.
+	ExamineMemory(address uintptr, length int) ([]byte, error)
+
 	// Disconnect closes the connection to the server without sending a Detach request first.
 	// If cont is true a continue command will be sent instead.
 	Disconnect(cont bool) error
diff --git a/service/dap/error_ids.go b/service/dap/error_ids.go
new file mode 100644
index 00000000..160314a8
--- /dev/null
+++ b/service/dap/error_ids.go
@@ -0,0 +1,15 @@
+package dap
+
+// Unique identifiers for messages returned for errors from requests.
+const (
+	UnsupportedCommand int = 9999
+
+	// The values below come from the vscode-go debug adaptor.
+	// Although the spec says they should be unique, the adaptor
+	// reuses 3000 for launch, attach and program exit failures.
+	// TODO(polina): confirm if the extension expects specific ids
+	// for specific cases, and we must match the existing adaptor
+	// or if these codes can evolve.
+	FailedToContinue = 3000
+	// Add more codes as we support more requests
+)
diff --git a/service/dap/server.go b/service/dap/server.go
new file mode 100644
index 00000000..dffb28d2
--- /dev/null
+++ b/service/dap/server.go
@@ -0,0 +1,466 @@
+package dap
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net"
+	"path/filepath"
+
+	"github.com/go-delve/delve/pkg/logflags"
+	"github.com/go-delve/delve/pkg/proc"
+	"github.com/go-delve/delve/service"
+	"github.com/go-delve/delve/service/api"
+	"github.com/go-delve/delve/service/debugger"
+	"github.com/google/go-dap"
+	"github.com/sirupsen/logrus"
+)
+
+// Package dap implements VSCode's Debug Adaptor Protocol (DAP).
+// This allows delve to communicate with frontends using DAP
+// without a separate adaptor. The frontend will run the debugger
+// (which now doubles as an adaptor) in server mode listening on
+// a port and communicating over TCP. This is work in progress,
+// so for now Delve in dap mode only supports synchronous
+// request-response communication, blocking while processing each request.
+// For DAP details see https://microsoft.github.io/debug-adapter-protocol.
+
+// Server implements a DAP server that can accept a single client for
+// a single debug session. It does not support restarting.
+// The server operates via two goroutines:
+// (1) Main goroutine where the server is created via NewServer(),
+// started via Run() and stopped via Stop().
+// (2) Run goroutine started from Run() that accepts a client connection,
+// reads, decodes and processes each request, issuing commands to the
+// underlying debugger and sending back events and responses.
+// TODO(polina): make it asynchronous (i.e. launch goroutine per request)
+type Server struct {
+	// config is all the information necessary to start the debugger and server.
+	config *service.Config
+	// listener is used to accept the client connection.
+	listener net.Listener
+	// conn is the accepted client connection.
+	conn net.Conn
+	// reader is used to read requests from the connection.
+	reader *bufio.Reader
+	// debugger is the underlying debugger service.
+	debugger *debugger.Debugger
+	// log is used for structured logging.
+	log *logrus.Entry
+	// stopOnEntry is set to automatically stop the debugee after start.
+	stopOnEntry bool
+}
+
+// NewServer creates a new DAP Server. It takes an opened Listener
+// via config and assumes its ownership. Optionally takes DisconnectChan
+// via config, which can be used to detect when the client disconnects
+// and the server is ready to be shut down. The caller must call
+// Stop() on shutdown.
+func NewServer(config *service.Config) *Server {
+	logger := logflags.DAPLogger()
+	logflags.WriteDAPListeningMessage(config.Listener.Addr().String())
+	return &Server{
+		config:   config,
+		listener: config.Listener,
+		log:      logger,
+	}
+}
+
+// Stop stops the DAP debugger service, closes the listener and
+// the client connection. It shuts down the underlying debugger
+// and kills the target process if it was launched by it.
+func (s *Server) Stop() {
+	s.listener.Close()
+	if s.conn != nil {
+		// Unless Stop() was called after serveDAPCodec()
+		// returned, this will result in closed connection error
+		// on next read, breaking out of the read loop and
+		// allowing the run goroutine to exit.
+		s.conn.Close()
+	}
+	if s.debugger != nil {
+		kill := s.config.AttachPid == 0
+		if err := s.debugger.Detach(kill); err != nil {
+			s.log.Error(err)
+		}
+	}
+}
+
+// signalDisconnect closes config.DisconnectChan if not nil, which
+// signals that the client disconnected or there was a client
+// connection failure. Since the server currently services only one
+// client, this can be used as a signal to the entire server via
+// Stop(). The function safeguards agaist closing the channel more
+// than once and can be called multiple times. It is not thread-safe
+// and is currently only called from the run goroutine.
+// TODO(polina): lock this when we add more goroutines that could call
+// this when we support asynchronous request-response communication.
+func (s *Server) signalDisconnect() {
+	// DisconnectChan might be nil at server creation if the
+	// caller does not want to rely on the disconnect signal.
+	if s.config.DisconnectChan != nil {
+		close(s.config.DisconnectChan)
+		// Take advantage of the nil check above to avoid accidentally
+		// closing the channel twice and causing a panic, when this
+		// function is called more than once. For example, we could
+		// have the following sequence of events:
+		// -- run goroutine: calls onDisconnectRequest()
+		// -- run goroutine: calls signalDisconnect()
+		// -- main goroutine: calls Stop()
+		// -- main goroutine: Stop() closes client connection
+		// -- run goroutine: serveDAPCodec() gets "closed network connection"
+		// -- run goroutine: serveDAPCodec() returns
+		// -- run goroutine: serveDAPCodec calls signalDisconnect()
+		s.config.DisconnectChan = nil
+	}
+}
+
+// Run launches a new goroutine where it accepts a client connection
+// and starts processing requests from it. Use Stop() to close connection.
+// The server does not support multiple clients, serially or in parallel.
+// The server should be restarted for every new debug session.
+// The debugger won't be started until launch/attach request is received.
+// TODO(polina): allow new client connections for new debug sessions,
+// so the editor needs to launch delve only once?
+func (s *Server) Run() {
+	go func() {
+		conn, err := s.listener.Accept()
+		if err != nil {
+			// This will print if the server is killed with Ctrl+C
+			// before client connection is accepted.
+			s.log.Errorf("Error accepting client connection: %s\n", err)
+			s.signalDisconnect()
+			return
+		}
+		s.conn = conn
+		s.serveDAPCodec()
+	}()
+}
+
+// serveDAPCodec reads and decodes requests from the client
+// until it encounters an error or EOF, when it sends
+// the disconnect signal and returns.
+func (s *Server) serveDAPCodec() {
+	defer s.signalDisconnect()
+	s.reader = bufio.NewReader(s.conn)
+	for {
+		request, err := dap.ReadProtocolMessage(s.reader)
+		// TODO(polina): Differentiate between errors and handle them
+		// gracefully. For example,
+		// -- "use of closed network connection" means client connection
+		// was closed via Stop() in response to a disconnect request.
+		// -- "Request command 'foo' is not supported" means we
+		// potentially got some new DAP request that we do not yet have
+		// decoding support for, so we can respond with an ErrorResponse.
+		// TODO(polina): to support this add Seq to
+		// dap.DecodeProtocolMessageFieldError.
+		if err != nil {
+			if err != io.EOF {
+				s.log.Error("DAP error: ", err)
+			}
+			return
+		}
+		// TODO(polina) Add a panic guard,
+		// so we do not kill user's process when delve panics.
+		s.handleRequest(request)
+	}
+}
+
+func (s *Server) handleRequest(request dap.Message) {
+	jsonmsg, _ := json.Marshal(request)
+	s.log.Debug("[<- from client]", string(jsonmsg))
+
+	switch request := request.(type) {
+	case *dap.InitializeRequest:
+		s.onInitializeRequest(request)
+	case *dap.LaunchRequest:
+		s.onLaunchRequest(request)
+	case *dap.AttachRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.DisconnectRequest:
+		s.onDisconnectRequest(request)
+	case *dap.TerminateRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.RestartRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.SetBreakpointsRequest:
+		s.onSetBreakpointsRequest(request)
+	case *dap.SetFunctionBreakpointsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.SetExceptionBreakpointsRequest:
+		s.onSetExceptionBreakpointsRequest(request)
+	case *dap.ConfigurationDoneRequest:
+		s.onConfigurationDoneRequest(request)
+	case *dap.ContinueRequest:
+		s.onContinueRequest(request)
+	case *dap.NextRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.StepInRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.StepOutRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.StepBackRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.ReverseContinueRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.RestartFrameRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.GotoRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.PauseRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.StackTraceRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.ScopesRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.VariablesRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.SetVariableRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.SetExpressionRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.SourceRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.ThreadsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.TerminateThreadsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.EvaluateRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.StepInTargetsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.GotoTargetsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.CompletionsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.ExceptionInfoRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.LoadedSourcesRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.DataBreakpointInfoRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.SetDataBreakpointsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.ReadMemoryRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.DisassembleRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.CancelRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	case *dap.BreakpointLocationsRequest:
+		s.sendUnsupportedErrorResponse(request.Request)
+	default:
+		// This is a DAP message that go-dap has a struct for, so
+		// decoding succeeded, but this function does not know how
+		// to handle. We should be sending an ErrorResponse, but
+		// we cannot get to Seq and other fields from dap.Message.
+		// TODO(polina): figure out how to handle this better.
+		// Consider adding GetSeq() method to dap.Message interface.
+		s.log.Errorf("Unable to process %#v\n", request)
+	}
+}
+
+func (s *Server) send(message dap.Message) {
+	jsonmsg, _ := json.Marshal(message)
+	s.log.Debug("[-> to client]", string(jsonmsg))
+	dap.WriteProtocolMessage(s.conn, message)
+}
+
+func (s *Server) onInitializeRequest(request *dap.InitializeRequest) {
+	// TODO(polina): Respond with an error if debug session is in progress?
+	response := &dap.InitializeResponse{Response: *newResponse(request.Request)}
+	response.Body.SupportsConfigurationDoneRequest = true
+	// TODO(polina): support this to match vscode-go functionality
+	response.Body.SupportsSetVariable = false
+	s.send(response)
+}
+
+func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
+	// TODO(polina): Respond with an error if debug session is in progress?
+	program, ok := request.Arguments["program"]
+	if !ok || program == "" {
+		s.sendErrorResponse(request.Request,
+			FailedToContinue, "Failed to launch",
+			"The program attribute is missing in debug configuration.")
+		return
+	}
+	s.config.ProcessArgs = []string{program.(string)}
+	s.config.WorkingDir = filepath.Dir(program.(string))
+	// TODO: support program args
+
+	stop, ok := request.Arguments["stopOnEntry"]
+	s.stopOnEntry = (ok && stop == true)
+
+	mode, ok := request.Arguments["mode"]
+	if !ok || mode == "" {
+		mode = "debug"
+	}
+	// TODO(polina): support "debug", "test" and "remote" modes
+	if mode != "exec" {
+		s.sendErrorResponse(request.Request,
+			FailedToContinue, "Failed to launch",
+			fmt.Sprintf("Unsupported 'mode' value '%s' in debug configuration.", mode))
+		return
+	}
+
+	config := &debugger.Config{
+		WorkingDir:           s.config.WorkingDir,
+		AttachPid:            0,
+		CoreFile:             "",
+		Backend:              s.config.Backend,
+		Foreground:           s.config.Foreground,
+		DebugInfoDirectories: s.config.DebugInfoDirectories,
+		CheckGoVersion:       s.config.CheckGoVersion,
+	}
+	var err error
+	if s.debugger, err = debugger.New(config, s.config.ProcessArgs); err != nil {
+		s.sendErrorResponse(request.Request,
+			FailedToContinue, "Failed to launch", err.Error())
+		return
+	}
+
+	// Notify the client that the debugger is ready to start accepting
+	// configuration requests for setting breakpoints, etc. The client
+	// will end the configuration sequence with 'configurationDone'.
+	s.send(&dap.InitializedEvent{Event: *newEvent("initialized")})
+	s.send(&dap.LaunchResponse{Response: *newResponse(request.Request)})
+}
+
+// onDisconnectRequest handles the DisconnectRequest. Per the DAP spec,
+// it disconnects the debuggee and signals that the debug adaptor
+// (in our case this TCP server) can be terminated.
+func (s *Server) onDisconnectRequest(request *dap.DisconnectRequest) {
+	s.send(&dap.DisconnectResponse{Response: *newResponse(request.Request)})
+	if s.debugger != nil {
+		_, err := s.debugger.Command(&api.DebuggerCommand{Name: api.Halt})
+		if err != nil {
+			s.log.Error(err)
+		}
+		kill := s.config.AttachPid == 0
+		err = s.debugger.Detach(kill)
+		if err != nil {
+			s.log.Error(err)
+		}
+	}
+	// TODO(polina): make thread-safe when handlers become asynchronous.
+	s.signalDisconnect()
+}
+
+func (s *Server) onSetBreakpointsRequest(request *dap.SetBreakpointsRequest) {
+	if request.Arguments.Source.Path == "" {
+		s.log.Error("ERROR: Unable to set breakpoint for empty file path")
+	}
+	response := &dap.SetBreakpointsResponse{Response: *newResponse(request.Request)}
+	response.Body.Breakpoints = make([]dap.Breakpoint, len(request.Arguments.Breakpoints))
+	// Only verified breakpoints will be set and reported back in the
+	// response. All breakpoints resulting in errors (e.g. duplicates
+	// or lines that do not have statements) will be skipped.
+	i := 0
+	for _, b := range request.Arguments.Breakpoints {
+		bp, err := s.debugger.CreateBreakpoint(
+			&api.Breakpoint{File: request.Arguments.Source.Path, Line: b.Line})
+		if err != nil {
+			s.log.Error("ERROR:", err)
+			continue
+		}
+		response.Body.Breakpoints[i].Verified = true
+		response.Body.Breakpoints[i].Line = bp.Line
+		i++
+	}
+	response.Body.Breakpoints = response.Body.Breakpoints[:i]
+	s.send(response)
+}
+
+func (s *Server) onSetExceptionBreakpointsRequest(request *dap.SetExceptionBreakpointsRequest) {
+	// Unlike what DAP documentation claims, this request is always sent
+	// even though we specified no filters at initializatin. Handle as no-op.
+	s.send(&dap.SetExceptionBreakpointsResponse{Response: *newResponse(request.Request)})
+}
+
+func (s *Server) onConfigurationDoneRequest(request *dap.ConfigurationDoneRequest) {
+	if s.stopOnEntry {
+		e := &dap.StoppedEvent{
+			Event: *newEvent("stopped"),
+			Body:  dap.StoppedEventBody{Reason: "breakpoint", ThreadId: 1, AllThreadsStopped: true},
+		}
+		s.send(e)
+	}
+	s.send(&dap.ConfigurationDoneResponse{Response: *newResponse(request.Request)})
+	if !s.stopOnEntry {
+		s.doContinue()
+	}
+}
+
+func (s *Server) onContinueRequest(request *dap.ContinueRequest) {
+	s.send(&dap.ContinueResponse{Response: *newResponse(request.Request)})
+	s.doContinue()
+}
+
+func (s *Server) sendErrorResponse(request dap.Request, id int, summary string, details string) {
+	er := &dap.ErrorResponse{}
+	er.Type = "response"
+	er.Command = request.Command
+	er.RequestSeq = request.Seq
+	er.Success = false
+	er.Message = summary
+	er.Body.Error.Id = id
+	er.Body.Error.Format = fmt.Sprintf("%s: %s", summary, details)
+	s.log.Error(er.Body.Error.Format)
+	s.send(er)
+}
+
+func (s *Server) sendUnsupportedErrorResponse(request dap.Request) {
+	s.sendErrorResponse(request, UnsupportedCommand, "Unsupported command",
+		fmt.Sprintf("cannot process '%s' request", request.Command))
+}
+
+func newResponse(request dap.Request) *dap.Response {
+	return &dap.Response{
+		ProtocolMessage: dap.ProtocolMessage{
+			Seq:  0,
+			Type: "response",
+		},
+		Command:    request.Command,
+		RequestSeq: request.Seq,
+		Success:    true,
+	}
+}
+
+func newEvent(event string) *dap.Event {
+	return &dap.Event{
+		ProtocolMessage: dap.ProtocolMessage{
+			Seq:  0,
+			Type: "event",
+		},
+		Event: event,
+	}
+}
+
+func (s *Server) doContinue() {
+	if s.debugger == nil {
+		return
+	}
+	state, err := s.debugger.Command(&api.DebuggerCommand{Name: api.Continue})
+	if err != nil {
+		s.log.Error(err)
+		switch err.(type) {
+		case proc.ErrProcessExited:
+			e := &dap.TerminatedEvent{Event: *newEvent("terminated")}
+			s.send(e)
+		default:
+		}
+		return
+	}
+	if state.Exited {
+		e := &dap.TerminatedEvent{Event: *newEvent("terminated")}
+		s.send(e)
+	} else {
+		e := &dap.StoppedEvent{Event: *newEvent("stopped")}
+		// TODO(polina): differentiate between breakpoint and pause on halt.
+		e.Body.Reason = "breakpoint"
+		e.Body.AllThreadsStopped = true
+		e.Body.ThreadId = state.SelectedGoroutine.ID
+		s.send(e)
+	}
+}
diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go
index da6a64bc..d508661b 100644
--- a/service/debugger/debugger.go
+++ b/service/debugger/debugger.go
@@ -961,7 +961,7 @@ func (d *Debugger) Registers(threadID int, floatingPoint bool) (api.Registers, e
 	if err != nil {
 		return nil, err
 	}
-	return api.ConvertRegisters(regs.Slice(floatingPoint)), err
+	return api.ConvertRegisters(regs.Slice(floatingPoint), d.target.BinInfo().Arch), err
 }
 
 func convertVars(pv []*proc.Variable) []api.Variable {
@@ -1313,6 +1313,25 @@ func (d *Debugger) ListDynamicLibraries() []api.Image {
 	return r
 }
 
+// ExamineMemory returns the raw memory stored at the given address.
+// The amount of data to be read is specified by length.
+// This function will return an error if it reads less than `length` bytes.
+func (d *Debugger) ExamineMemory(address uintptr, length int) ([]byte, error) {
+	d.processMutex.Lock()
+	defer d.processMutex.Unlock()
+
+	thread := d.target.CurrentThread()
+	data := make([]byte, length)
+	n, err := thread.ReadMemory(data, address)
+	if err != nil {
+		return nil, err
+	}
+	if length != n {
+		return nil, errors.New("the specific range has exceeded readable area")
+	}
+	return data, nil
+}
+
 func (d *Debugger) GetVersion(out *api.GetVersionOut) error {
 	if d.config.CoreFile != "" {
 		if d.config.Backend == "rr" {
diff --git a/service/rpc2/client.go b/service/rpc2/client.go
index 6f2f31db..51edc953 100644
--- a/service/rpc2/client.go
+++ b/service/rpc2/client.go
@@ -413,6 +413,17 @@ func (c *RPCClient) ListDynamicLibraries() ([]api.Image, error) {
 	return out.List, nil
 }
 
+func (c *RPCClient) ExamineMemory(address uintptr, count int) ([]byte, error) {
+	out := &ExaminedMemoryOut{}
+
+	err := c.call("ExamineMemory", ExamineMemoryIn{Length: count, Address: address}, out)
+	if err != nil {
+		return nil, err
+	}
+
+	return out.Mem, nil
+}
+
 func (c *RPCClient) call(method string, args, reply interface{}) error {
 	return c.client.Call("RPCServer."+method, args, reply)
 }
diff --git a/service/rpc2/server.go b/service/rpc2/server.go
index 68b84c6d..defbe212 100644
--- a/service/rpc2/server.go
+++ b/service/rpc2/server.go
@@ -751,3 +751,27 @@ func (s *RPCServer) ListPackagesBuildInfo(in ListPackagesBuildInfoIn, out *ListP
 	out.List = s.debugger.ListPackagesBuildInfo(in.IncludeFiles)
 	return nil
 }
+
+// ExamineMemoryIn holds the arguments of ExamineMemory
+type ExamineMemoryIn struct {
+	Address uintptr
+	Length  int
+}
+
+// ExaminedMemoryOut holds the return values of ExamineMemory
+type ExaminedMemoryOut struct {
+	Mem []byte
+}
+
+func (s *RPCServer) ExamineMemory(arg ExamineMemoryIn, out *ExaminedMemoryOut) error {
+	if arg.Length > 1000 {
+		return fmt.Errorf("len must be less than or equal to 1000")
+	}
+	Mem, err := s.debugger.ExamineMemory(arg.Address, arg.Length)
+	if err != nil {
+		return err
+	}
+
+	out.Mem = Mem
+	return nil
+}
diff --git a/vendor/github.com/google/go-dap/.travis.yml b/vendor/github.com/google/go-dap/.travis.yml
new file mode 100644
index 00000000..54bc099d
--- /dev/null
+++ b/vendor/github.com/google/go-dap/.travis.yml
@@ -0,0 +1,12 @@
+language: go
+
+go:
+- 1.13.x
+
+env:
+  global:
+  - GOPROXY=https://proxy.golang.org
+  - GO111MODULE=on
+
+script:
+  - 'internal/test.sh'
diff --git a/vendor/github.com/google/go-dap/LICENSE b/vendor/github.com/google/go-dap/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/vendor/github.com/google/go-dap/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/github.com/google/go-dap/README.md b/vendor/github.com/google/go-dap/README.md
new file mode 100644
index 00000000..bfec6168
--- /dev/null
+++ b/vendor/github.com/google/go-dap/README.md
@@ -0,0 +1,19 @@
+# go-dap: Go implementation of the Debug Adapter Protocol
+
+[![Build Status](https://travis-ci.org/google/go-dap.svg?branch=master)](https://travis-ci.org/google/go-dap)
+[![Go Report Card](https://goreportcard.com/badge/github.com/google/go-dap)](https://goreportcard.com/report/github.com/google/go-dap)
+
+For an overview of DAP, see
+https://microsoft.github.io/debug-adapter-protocol/overview
+
+## Contributing
+
+We'd love to accept your patches and contributions to this project. See
+[docs/contributing](https://github.com/google/go-dap/blob/master/docs/contributing.md)
+for more details.
+
+## License
+
+This project is licensed under the Apache License 2.0
+
+This is not an officially supported Google product.
diff --git a/vendor/github.com/google/go-dap/codec.go b/vendor/github.com/google/go-dap/codec.go
new file mode 100644
index 00000000..34c689f5
--- /dev/null
+++ b/vendor/github.com/google/go-dap/codec.go
@@ -0,0 +1,219 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains utilities for decoding JSON-encoded bytes into DAP message.
+
+package dap
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+// DecodeProtocolMessageFieldError describes which JSON attribute
+// has an unsupported value that the decoding cannot handle.
+type DecodeProtocolMessageFieldError struct {
+	SubType    string
+	FieldName  string
+	FieldValue string
+}
+
+func (e *DecodeProtocolMessageFieldError) Error() string {
+	return fmt.Sprintf("%s %s '%s' is not supported", e.SubType, e.FieldName, e.FieldValue)
+}
+
+// DecodeProtocolMessage parses the JSON-encoded data and returns the result of
+// the appropriate type within the ProtocolMessage hierarchy. If message type,
+// command, etc cannot be cast, returns DecodeProtocolMessageFieldError.
+// See also godoc for json.Unmarshal, which is used for underlying decoding.
+func DecodeProtocolMessage(data []byte) (Message, error) {
+	var protomsg ProtocolMessage
+	if err := json.Unmarshal(data, &protomsg); err != nil {
+		return nil, err
+	}
+	switch protomsg.Type {
+	case "request":
+		return decodeRequest(data)
+	case "response":
+		return decodeResponse(data)
+	case "event":
+		return decodeEvent(data)
+	default:
+		return nil, &DecodeProtocolMessageFieldError{"ProtocolMessage", "type", protomsg.Type}
+	}
+}
+
+type messageCtor func() Message
+
+// decodeRequest determines what request type in the ProtocolMessage hierarchy
+// data corresponds to and uses json.Unmarshal to populate the corresponding
+// struct to be returned.
+func decodeRequest(data []byte) (Message, error) {
+	var r Request
+	if err := json.Unmarshal(data, &r); err != nil {
+		return nil, err
+	}
+	if ctor, ok := requestCtor[r.Command]; ok {
+		requestPtr := ctor()
+		err := json.Unmarshal(data, requestPtr)
+		return requestPtr, err
+	}
+	return nil, &DecodeProtocolMessageFieldError{"Request", "command", r.Command}
+}
+
+// Mapping of request commands and corresponding struct constructors that
+// can be passed to json.Unmarshal.
+var requestCtor = map[string]messageCtor{
+	"cancel":                  func() Message { return &CancelRequest{} },
+	"runInTerminal":           func() Message { return &RunInTerminalRequest{} },
+	"initialize":              func() Message { return &InitializeRequest{} },
+	"configurationDone":       func() Message { return &ConfigurationDoneRequest{} },
+	"launch":                  func() Message { return &LaunchRequest{} },
+	"attach":                  func() Message { return &AttachRequest{} },
+	"restart":                 func() Message { return &RestartRequest{} },
+	"disconnect":              func() Message { return &DisconnectRequest{} },
+	"terminate":               func() Message { return &TerminateRequest{} },
+	"breakpointLocations":     func() Message { return &BreakpointLocationsRequest{} },
+	"setBreakpoints":          func() Message { return &SetBreakpointsRequest{} },
+	"setFunctionBreakpoints":  func() Message { return &SetFunctionBreakpointsRequest{} },
+	"setExceptionBreakpoints": func() Message { return &SetExceptionBreakpointsRequest{} },
+	"dataBreakpointInfo":      func() Message { return &DataBreakpointInfoRequest{} },
+	"setDataBreakpoints":      func() Message { return &SetDataBreakpointsRequest{} },
+	"continue":                func() Message { return &ContinueRequest{} },
+	"next":                    func() Message { return &NextRequest{} },
+	"stepIn":                  func() Message { return &StepInRequest{} },
+	"stepOut":                 func() Message { return &StepOutRequest{} },
+	"stepBack":                func() Message { return &StepBackRequest{} },
+	"reverseContinue":         func() Message { return &ReverseContinueRequest{} },
+	"restartFrame":            func() Message { return &RestartFrameRequest{} },
+	"goto":                    func() Message { return &GotoRequest{} },
+	"pause":                   func() Message { return &PauseRequest{} },
+	"stackTrace":              func() Message { return &StackTraceRequest{} },
+	"scopes":                  func() Message { return &ScopesRequest{} },
+	"variables":               func() Message { return &VariablesRequest{} },
+	"setVariable":             func() Message { return &SetVariableRequest{} },
+	"source":                  func() Message { return &SourceRequest{} },
+	"threads":                 func() Message { return &ThreadsRequest{} },
+	"terminateThreads":        func() Message { return &TerminateThreadsRequest{} },
+	"modules":                 func() Message { return &ModulesRequest{} },
+	"loadedSources":           func() Message { return &LoadedSourcesRequest{} },
+	"evaluate":                func() Message { return &EvaluateRequest{} },
+	"setExpression":           func() Message { return &SetExpressionRequest{} },
+	"stepInTargets":           func() Message { return &StepInTargetsRequest{} },
+	"gotoTargets":             func() Message { return &GotoTargetsRequest{} },
+	"completions":             func() Message { return &CompletionsRequest{} },
+	"exceptionInfo":           func() Message { return &ExceptionInfoRequest{} },
+	"readMemory":              func() Message { return &ReadMemoryRequest{} },
+	"disassemble":             func() Message { return &DisassembleRequest{} },
+}
+
+// decodeResponse determines what response type in the ProtocolMessage hierarchy
+// data corresponds to and uses json.Unmarshal to populate the corresponding
+// struct to be returned.
+func decodeResponse(data []byte) (Message, error) {
+	var r Response
+	if err := json.Unmarshal(data, &r); err != nil {
+		return nil, err
+	}
+	if !r.Success {
+		var er ErrorResponse
+		err := json.Unmarshal(data, &er)
+		return &er, err
+	}
+	if ctor, ok := responseCtor[r.Command]; ok {
+		responsePtr := ctor()
+		err := json.Unmarshal(data, responsePtr)
+		return responsePtr, err
+	}
+	return nil, &DecodeProtocolMessageFieldError{"Response", "command", r.Command}
+}
+
+// Mapping of response commands and corresponding struct constructors that
+// can be passed to json.Unmarshal.
+var responseCtor = map[string]messageCtor{
+	"cancel":                  func() Message { return &CancelResponse{} },
+	"runInTerminal":           func() Message { return &RunInTerminalResponse{} },
+	"initialize":              func() Message { return &InitializeResponse{} },
+	"configurationDone":       func() Message { return &ConfigurationDoneResponse{} },
+	"launch":                  func() Message { return &LaunchResponse{} },
+	"attach":                  func() Message { return &AttachResponse{} },
+	"restart":                 func() Message { return &RestartResponse{} },
+	"disconnect":              func() Message { return &DisconnectResponse{} },
+	"terminate":               func() Message { return &TerminateResponse{} },
+	"breakpointLocations":     func() Message { return &BreakpointLocationsResponse{} },
+	"setBreakpoints":          func() Message { return &SetBreakpointsResponse{} },
+	"setFunctionBreakpoints":  func() Message { return &SetFunctionBreakpointsResponse{} },
+	"setExceptionBreakpoints": func() Message { return &SetExceptionBreakpointsResponse{} },
+	"dataBreakpointInfo":      func() Message { return &DataBreakpointInfoResponse{} },
+	"setDataBreakpoints":      func() Message { return &SetDataBreakpointsResponse{} },
+	"continue":                func() Message { return &ContinueResponse{} },
+	"next":                    func() Message { return &NextResponse{} },
+	"stepIn":                  func() Message { return &StepInResponse{} },
+	"stepOut":                 func() Message { return &StepOutResponse{} },
+	"stepBack":                func() Message { return &StepBackResponse{} },
+	"reverseContinue":         func() Message { return &ReverseContinueResponse{} },
+	"restartFrame":            func() Message { return &RestartFrameResponse{} },
+	"goto":                    func() Message { return &GotoResponse{} },
+	"pause":                   func() Message { return &PauseResponse{} },
+	"stackTrace":              func() Message { return &StackTraceResponse{} },
+	"scopes":                  func() Message { return &ScopesResponse{} },
+	"variables":               func() Message { return &VariablesResponse{} },
+	"setVariable":             func() Message { return &SetVariableResponse{} },
+	"source":                  func() Message { return &SourceResponse{} },
+	"threads":                 func() Message { return &ThreadsResponse{} },
+	"terminateThreads":        func() Message { return &TerminateThreadsResponse{} },
+	"modules":                 func() Message { return &ModulesResponse{} },
+	"loadedSources":           func() Message { return &LoadedSourcesResponse{} },
+	"evaluate":                func() Message { return &EvaluateResponse{} },
+	"setExpression":           func() Message { return &SetExpressionResponse{} },
+	"stepInTargets":           func() Message { return &StepInTargetsResponse{} },
+	"gotoTargets":             func() Message { return &GotoTargetsResponse{} },
+	"completions":             func() Message { return &CompletionsResponse{} },
+	"exceptionInfo":           func() Message { return &ExceptionInfoResponse{} },
+	"readMemory":              func() Message { return &ReadMemoryResponse{} },
+	"disassemble":             func() Message { return &DisassembleResponse{} },
+}
+
+// decodeEvent determines what event type in the ProtocolMessage hierarchy
+// data corresponds to and uses json.Unmarshal to populate the corresponding
+// struct to be returned.
+func decodeEvent(data []byte) (Message, error) {
+	var e Event
+	if err := json.Unmarshal(data, &e); err != nil {
+		return nil, err
+	}
+	if ctor, ok := eventCtor[e.Event]; ok {
+		eventPtr := ctor()
+		err := json.Unmarshal(data, eventPtr)
+		return eventPtr, err
+	}
+	return nil, &DecodeProtocolMessageFieldError{"Event", "event", e.Event}
+}
+
+// Mapping of event ids and corresponding struct constructors that
+// can be passed to json.Unmarshal.
+var eventCtor = map[string]messageCtor{
+	"initialized":  func() Message { return &InitializedEvent{} },
+	"stopped":      func() Message { return &StoppedEvent{} },
+	"continued":    func() Message { return &ContinuedEvent{} },
+	"exited":       func() Message { return &ExitedEvent{} },
+	"terminated":   func() Message { return &TerminatedEvent{} },
+	"thread":       func() Message { return &ThreadEvent{} },
+	"output":       func() Message { return &OutputEvent{} },
+	"breakpoint":   func() Message { return &BreakpointEvent{} },
+	"module":       func() Message { return &ModuleEvent{} },
+	"loadedSource": func() Message { return &LoadedSourceEvent{} },
+	"process":      func() Message { return &ProcessEvent{} },
+	"capabilities": func() Message { return &CapabilitiesEvent{} },
+}
diff --git a/vendor/github.com/google/go-dap/go.mod b/vendor/github.com/google/go-dap/go.mod
new file mode 100644
index 00000000..6a37a239
--- /dev/null
+++ b/vendor/github.com/google/go-dap/go.mod
@@ -0,0 +1,3 @@
+module github.com/google/go-dap
+
+go 1.13
diff --git a/vendor/github.com/google/go-dap/io.go b/vendor/github.com/google/go-dap/io.go
new file mode 100644
index 00000000..a06c8310
--- /dev/null
+++ b/vendor/github.com/google/go-dap/io.go
@@ -0,0 +1,137 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains utilities for DAP Base protocol I/O.
+// For additional information, see "Base protocol" section in
+// https://microsoft.github.io/debug-adapter-protocol/overview.
+
+package dap
+
+import (
+	"bufio"
+	"encoding/json"
+	"fmt"
+	"io"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// BaseProtocolError represents base protocol error, which occurs when the raw
+// message does not conform to the header+content format of the base protocol.
+type BaseProtocolError struct {
+	Err string
+}
+
+func (bpe *BaseProtocolError) Error() string { return bpe.Err }
+
+var (
+	// ErrHeaderDelimiterNotCrLfCrLf is returned when only partial header
+	// delimiter \r\n\r\n is encountered.
+	ErrHeaderDelimiterNotCrLfCrLf = &BaseProtocolError{fmt.Sprintf("header delimiter is not %q", crLfcrLf)}
+
+	// ErrHeaderNotContentLength is returned when the parsed header is
+	// not of valid Content-Length format.
+	ErrHeaderNotContentLength = &BaseProtocolError{fmt.Sprintf("header format is not %q", contentLengthHeaderRegex)}
+
+	// ErrHeaderContentTooLong is returned when the content length specified in
+	// the header is above contentMaxLength.
+	ErrHeaderContentTooLong = &BaseProtocolError{fmt.Sprintf("content length over %v bytes", contentMaxLength)}
+)
+
+const (
+	crLfcrLf               = "\r\n\r\n"
+	contentLengthHeaderFmt = "Content-Length: %d\r\n\r\n"
+	contentMaxLength       = 4 * 1024 * 1024
+)
+
+var (
+	contentLengthHeaderRegex = regexp.MustCompile("^Content-Length: ([0-9]+)$")
+)
+
+// WriteBaseMessage formats content with Content-Length header and delimiters
+// as per the base protocol and writes the resulting message to w.
+func WriteBaseMessage(w io.Writer, content []byte) error {
+	header := fmt.Sprintf(contentLengthHeaderFmt, len(content))
+	if _, err := w.Write([]byte(header)); err != nil {
+		return err
+	}
+	_, err := w.Write(content)
+	return err
+}
+
+// ReadBaseMessage reads one message from r consisting of a Content-Length
+// header and a content part. It parses the header to determine the size of
+// the content part and extracts and returns the actual content of the message.
+// Returns nil bytes on error, which can be one of the standard IO errors or
+// a BaseProtocolError defined in this package.
+func ReadBaseMessage(r *bufio.Reader) ([]byte, error) {
+	contentLength, err := readContentLengthHeader(r)
+	if err != nil {
+		return nil, err
+	}
+	if contentLength > contentMaxLength {
+		return nil, ErrHeaderContentTooLong
+	}
+	content := make([]byte, contentLength)
+	if _, err = io.ReadFull(r, content); err != nil {
+		return nil, err
+	}
+	return content, nil
+}
+
+// readContentLengthHeader looks for the only header field that is supported
+// and required:
+// 		Content-Length: [0-9]+\r\n\r\n
+// Extracts and returns the content length.
+func readContentLengthHeader(r *bufio.Reader) (contentLength int, err error) {
+	// Look for <some header>\r\n\r\n
+	headerWithCr, err := r.ReadString('\r')
+	if err != nil {
+		return 0, err
+	}
+	nextThree := make([]byte, 3)
+	if _, err = io.ReadFull(r, nextThree); err != nil {
+		return 0, err
+	}
+	if string(nextThree) != "\n\r\n" {
+		return 0, ErrHeaderDelimiterNotCrLfCrLf
+	}
+
+	// If header is in the right format, get the length
+	header := strings.TrimSuffix(headerWithCr, "\r")
+	headerAndLength := contentLengthHeaderRegex.FindStringSubmatch(header)
+	if len(headerAndLength) < 2 {
+		return 0, ErrHeaderNotContentLength
+	}
+	return strconv.Atoi(headerAndLength[1])
+}
+
+// WriteProtocolMessage encodes message and writes it to w.
+func WriteProtocolMessage(w io.Writer, message Message) error {
+	b, err := json.Marshal(message)
+	if err != nil {
+		return err
+	}
+	return WriteBaseMessage(w, b)
+}
+
+// ReadProtocolMessage reads a message from r, decodes and returns it.
+func ReadProtocolMessage(r *bufio.Reader) (Message, error) {
+	content, err := ReadBaseMessage(r)
+	if err != nil {
+		return nil, err
+	}
+	return DecodeProtocolMessage(content)
+}
diff --git a/vendor/github.com/google/go-dap/schematypes.go b/vendor/github.com/google/go-dap/schematypes.go
new file mode 100644
index 00000000..5f905865
--- /dev/null
+++ b/vendor/github.com/google/go-dap/schematypes.go
@@ -0,0 +1,1589 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// DO NOT EDIT: This file is auto-generated.
+// DAP spec: https://microsoft.github.io/debug-adapter-protocol/specification
+// See cmd/gentypes/README.md for additional details.
+
+package dap
+
+// Message is an interface that all DAP message types implement with pointer
+// receivers. It's not part of the protocol but is used to enforce static
+// typing in Go code.
+//
+// Note: the DAP type "Message" (which is used in the body of ErrorResponse)
+// is renamed to ErrorMessage to avoid collision with this interface.
+type Message interface {
+	isMessage()
+}
+
+// ProtocolMessage: Base class of requests, responses, and events.
+type ProtocolMessage struct {
+	Seq  int    `json:"seq"`
+	Type string `json:"type"`
+}
+
+// Request: A client or debug adapter initiated request.
+type Request struct {
+	ProtocolMessage
+
+	Command string `json:"command"`
+}
+
+// Event: A debug adapter initiated event.
+type Event struct {
+	ProtocolMessage
+
+	Event string `json:"event"`
+}
+
+// Response: Response for a request.
+type Response struct {
+	ProtocolMessage
+
+	RequestSeq int    `json:"request_seq"`
+	Success    bool   `json:"success"`
+	Command    string `json:"command"`
+	Message    string `json:"message,omitempty"`
+}
+
+// ErrorResponse: On error (whenever 'success' is false), the body can provide more details.
+type ErrorResponse struct {
+	Response
+
+	Body ErrorResponseBody `json:"body"`
+}
+
+type ErrorResponseBody struct {
+	Error ErrorMessage `json:"error,omitempty"`
+}
+
+// CancelRequest: The 'cancel' request is used by the frontend to indicate that it is no longer interested in the result produced by a specific request issued earlier.
+// This request has a hint characteristic: a debug adapter can only be expected to make a 'best effort' in honouring this request but there are no guarantees.
+// The 'cancel' request may return an error if it could not cancel an operation but a frontend should refrain from presenting this error to end users.
+// A frontend client should only call this request if the capability 'supportsCancelRequest' is true.
+// The request that got canceled still needs to send a response back.
+// This can either be a normal result ('success' attribute true) or an error response ('success' attribute false and the 'message' set to 'cancelled').
+// Returning partial results from a cancelled request is possible but please note that a frontend client has no generic way for detecting that a response is partial or not.
+type CancelRequest struct {
+	Request
+
+	Arguments CancelArguments `json:"arguments,omitempty"`
+}
+
+// CancelArguments: Arguments for 'cancel' request.
+type CancelArguments struct {
+	RequestId int `json:"requestId,omitempty"`
+}
+
+// CancelResponse: Response to 'cancel' request. This is just an acknowledgement, so no body field is required.
+type CancelResponse struct {
+	Response
+}
+
+// InitializedEvent: This event indicates that the debug adapter is ready to accept configuration requests (e.g. SetBreakpointsRequest, SetExceptionBreakpointsRequest).
+// A debug adapter is expected to send this event when it is ready to accept configuration requests (but not before the 'initialize' request has finished).
+// The sequence of events/requests is as follows:
+// - adapters sends 'initialized' event (after the 'initialize' request has returned)
+// - frontend sends zero or more 'setBreakpoints' requests
+// - frontend sends one 'setFunctionBreakpoints' request
+// - frontend sends a 'setExceptionBreakpoints' request if one or more 'exceptionBreakpointFilters' have been defined (or if 'supportsConfigurationDoneRequest' is not defined or false)
+// - frontend sends other future configuration requests
+// - frontend sends one 'configurationDone' request to indicate the end of the configuration.
+type InitializedEvent struct {
+	Event
+}
+
+// StoppedEvent: The event indicates that the execution of the debuggee has stopped due to some condition.
+// This can be caused by a break point previously set, a stepping action has completed, by executing a debugger statement etc.
+type StoppedEvent struct {
+	Event
+
+	Body StoppedEventBody `json:"body"`
+}
+
+type StoppedEventBody struct {
+	Reason            string `json:"reason"`
+	Description       string `json:"description,omitempty"`
+	ThreadId          int    `json:"threadId,omitempty"`
+	PreserveFocusHint bool   `json:"preserveFocusHint,omitempty"`
+	Text              string `json:"text,omitempty"`
+	AllThreadsStopped bool   `json:"allThreadsStopped,omitempty"`
+}
+
+// ContinuedEvent: The event indicates that the execution of the debuggee has continued.
+// Please note: a debug adapter is not expected to send this event in response to a request that implies that execution continues, e.g. 'launch' or 'continue'.
+// It is only necessary to send a 'continued' event if there was no previous request that implied this.
+type ContinuedEvent struct {
+	Event
+
+	Body ContinuedEventBody `json:"body"`
+}
+
+type ContinuedEventBody struct {
+	ThreadId            int  `json:"threadId"`
+	AllThreadsContinued bool `json:"allThreadsContinued,omitempty"`
+}
+
+// ExitedEvent: The event indicates that the debuggee has exited and returns its exit code.
+type ExitedEvent struct {
+	Event
+
+	Body ExitedEventBody `json:"body"`
+}
+
+type ExitedEventBody struct {
+	ExitCode int `json:"exitCode"`
+}
+
+// TerminatedEvent: The event indicates that debugging of the debuggee has terminated. This does **not** mean that the debuggee itself has exited.
+type TerminatedEvent struct {
+	Event
+
+	Body TerminatedEventBody `json:"body,omitempty"`
+}
+
+type TerminatedEventBody struct {
+	Restart interface{} `json:"restart,omitempty"`
+}
+
+// ThreadEvent: The event indicates that a thread has started or exited.
+type ThreadEvent struct {
+	Event
+
+	Body ThreadEventBody `json:"body"`
+}
+
+type ThreadEventBody struct {
+	Reason   string `json:"reason"`
+	ThreadId int    `json:"threadId"`
+}
+
+// OutputEvent: The event indicates that the target has produced some output.
+type OutputEvent struct {
+	Event
+
+	Body OutputEventBody `json:"body"`
+}
+
+type OutputEventBody struct {
+	Category           string      `json:"category,omitempty"`
+	Output             string      `json:"output"`
+	VariablesReference int         `json:"variablesReference,omitempty"`
+	Source             Source      `json:"source,omitempty"`
+	Line               int         `json:"line,omitempty"`
+	Column             int         `json:"column,omitempty"`
+	Data               interface{} `json:"data,omitempty"`
+}
+
+// BreakpointEvent: The event indicates that some information about a breakpoint has changed.
+type BreakpointEvent struct {
+	Event
+
+	Body BreakpointEventBody `json:"body"`
+}
+
+type BreakpointEventBody struct {
+	Reason     string     `json:"reason"`
+	Breakpoint Breakpoint `json:"breakpoint"`
+}
+
+// ModuleEvent: The event indicates that some information about a module has changed.
+type ModuleEvent struct {
+	Event
+
+	Body ModuleEventBody `json:"body"`
+}
+
+type ModuleEventBody struct {
+	Reason string `json:"reason"`
+	Module Module `json:"module"`
+}
+
+// LoadedSourceEvent: The event indicates that some source has been added, changed, or removed from the set of all loaded sources.
+type LoadedSourceEvent struct {
+	Event
+
+	Body LoadedSourceEventBody `json:"body"`
+}
+
+type LoadedSourceEventBody struct {
+	Reason string `json:"reason"`
+	Source Source `json:"source"`
+}
+
+// ProcessEvent: The event indicates that the debugger has begun debugging a new process. Either one that it has launched, or one that it has attached to.
+type ProcessEvent struct {
+	Event
+
+	Body ProcessEventBody `json:"body"`
+}
+
+type ProcessEventBody struct {
+	Name            string `json:"name"`
+	SystemProcessId int    `json:"systemProcessId,omitempty"`
+	IsLocalProcess  bool   `json:"isLocalProcess,omitempty"`
+	StartMethod     string `json:"startMethod,omitempty"`
+	PointerSize     int    `json:"pointerSize,omitempty"`
+}
+
+// CapabilitiesEvent: The event indicates that one or more capabilities have changed.
+// Since the capabilities are dependent on the frontend and its UI, it might not be possible to change that at random times (or too late).
+// Consequently this event has a hint characteristic: a frontend can only be expected to make a 'best effort' in honouring individual capabilities but there are no guarantees.
+// Only changed capabilities need to be included, all other capabilities keep their values.
+type CapabilitiesEvent struct {
+	Event
+
+	Body CapabilitiesEventBody `json:"body"`
+}
+
+type CapabilitiesEventBody struct {
+	Capabilities Capabilities `json:"capabilities"`
+}
+
+// RunInTerminalRequest: This request is sent from the debug adapter to the client to run a command in a terminal. This is typically used to launch the debuggee in a terminal provided by the client.
+type RunInTerminalRequest struct {
+	Request
+
+	Arguments RunInTerminalRequestArguments `json:"arguments"`
+}
+
+// RunInTerminalRequestArguments: Arguments for 'runInTerminal' request.
+type RunInTerminalRequestArguments struct {
+	Kind  string                 `json:"kind,omitempty"`
+	Title string                 `json:"title,omitempty"`
+	Cwd   string                 `json:"cwd"`
+	Args  []string               `json:"args"`
+	Env   map[string]interface{} `json:"env,omitempty"`
+}
+
+// RunInTerminalResponse: Response to 'runInTerminal' request.
+type RunInTerminalResponse struct {
+	Response
+
+	Body RunInTerminalResponseBody `json:"body"`
+}
+
+type RunInTerminalResponseBody struct {
+	ProcessId      int `json:"processId,omitempty"`
+	ShellProcessId int `json:"shellProcessId,omitempty"`
+}
+
+// InitializeRequest: The 'initialize' request is sent as the first request from the client to the debug adapter in order to configure it with client capabilities and to retrieve capabilities from the debug adapter.
+// Until the debug adapter has responded to with an 'initialize' response, the client must not send any additional requests or events to the debug adapter. In addition the debug adapter is not allowed to send any requests or events to the client until it has responded with an 'initialize' response.
+// The 'initialize' request may only be sent once.
+type InitializeRequest struct {
+	Request
+
+	Arguments InitializeRequestArguments `json:"arguments"`
+}
+
+// InitializeRequestArguments: Arguments for 'initialize' request.
+type InitializeRequestArguments struct {
+	ClientID                     string `json:"clientID,omitempty"`
+	ClientName                   string `json:"clientName,omitempty"`
+	AdapterID                    string `json:"adapterID"`
+	Locale                       string `json:"locale,omitempty"`
+	LinesStartAt1                bool   `json:"linesStartAt1,omitempty"`
+	ColumnsStartAt1              bool   `json:"columnsStartAt1,omitempty"`
+	PathFormat                   string `json:"pathFormat,omitempty"`
+	SupportsVariableType         bool   `json:"supportsVariableType,omitempty"`
+	SupportsVariablePaging       bool   `json:"supportsVariablePaging,omitempty"`
+	SupportsRunInTerminalRequest bool   `json:"supportsRunInTerminalRequest,omitempty"`
+	SupportsMemoryReferences     bool   `json:"supportsMemoryReferences,omitempty"`
+}
+
+// InitializeResponse: Response to 'initialize' request.
+type InitializeResponse struct {
+	Response
+
+	Body Capabilities `json:"body,omitempty"`
+}
+
+// ConfigurationDoneRequest: The client of the debug protocol must send this request at the end of the sequence of configuration requests (which was started by the 'initialized' event).
+type ConfigurationDoneRequest struct {
+	Request
+
+	Arguments ConfigurationDoneArguments `json:"arguments,omitempty"`
+}
+
+// ConfigurationDoneArguments: Arguments for 'configurationDone' request.
+type ConfigurationDoneArguments struct {
+}
+
+// ConfigurationDoneResponse: Response to 'configurationDone' request. This is just an acknowledgement, so no body field is required.
+type ConfigurationDoneResponse struct {
+	Response
+}
+
+// LaunchRequest: The launch request is sent from the client to the debug adapter to start the debuggee with or without debugging (if 'noDebug' is true). Since launching is debugger/runtime specific, the arguments for this request are not part of this specification.
+type LaunchRequest struct {
+	Request
+
+	Arguments map[string]interface{} `json:"arguments"`
+}
+
+// LaunchResponse: Response to 'launch' request. This is just an acknowledgement, so no body field is required.
+type LaunchResponse struct {
+	Response
+}
+
+// AttachRequest: The attach request is sent from the client to the debug adapter to attach to a debuggee that is already running. Since attaching is debugger/runtime specific, the arguments for this request are not part of this specification.
+type AttachRequest struct {
+	Request
+
+	Arguments AttachRequestArguments `json:"arguments"`
+}
+
+// AttachRequestArguments: Arguments for 'attach' request. Additional attributes are implementation specific.
+type AttachRequestArguments struct {
+	Restart interface{} `json:"__restart,omitempty"`
+}
+
+// AttachResponse: Response to 'attach' request. This is just an acknowledgement, so no body field is required.
+type AttachResponse struct {
+	Response
+}
+
+// RestartRequest: Restarts a debug session. If the capability 'supportsRestartRequest' is missing or has the value false,
+// the client will implement 'restart' by terminating the debug adapter first and then launching it anew.
+// A debug adapter can override this default behaviour by implementing a restart request
+// and setting the capability 'supportsRestartRequest' to true.
+type RestartRequest struct {
+	Request
+
+	Arguments RestartArguments `json:"arguments,omitempty"`
+}
+
+// RestartArguments: Arguments for 'restart' request.
+type RestartArguments struct {
+}
+
+// RestartResponse: Response to 'restart' request. This is just an acknowledgement, so no body field is required.
+type RestartResponse struct {
+	Response
+}
+
+// DisconnectRequest: The 'disconnect' request is sent from the client to the debug adapter in order to stop debugging. It asks the debug adapter to disconnect from the debuggee and to terminate the debug adapter. If the debuggee has been started with the 'launch' request, the 'disconnect' request terminates the debuggee. If the 'attach' request was used to connect to the debuggee, 'disconnect' does not terminate the debuggee. This behavior can be controlled with the 'terminateDebuggee' argument (if supported by the debug adapter).
+type DisconnectRequest struct {
+	Request
+
+	Arguments DisconnectArguments `json:"arguments,omitempty"`
+}
+
+// DisconnectArguments: Arguments for 'disconnect' request.
+type DisconnectArguments struct {
+	Restart           bool `json:"restart,omitempty"`
+	TerminateDebuggee bool `json:"terminateDebuggee,omitempty"`
+}
+
+// DisconnectResponse: Response to 'disconnect' request. This is just an acknowledgement, so no body field is required.
+type DisconnectResponse struct {
+	Response
+}
+
+// TerminateRequest: The 'terminate' request is sent from the client to the debug adapter in order to give the debuggee a chance for terminating itself.
+type TerminateRequest struct {
+	Request
+
+	Arguments TerminateArguments `json:"arguments,omitempty"`
+}
+
+// TerminateArguments: Arguments for 'terminate' request.
+type TerminateArguments struct {
+	Restart bool `json:"restart,omitempty"`
+}
+
+// TerminateResponse: Response to 'terminate' request. This is just an acknowledgement, so no body field is required.
+type TerminateResponse struct {
+	Response
+}
+
+// BreakpointLocationsRequest: The 'breakpointLocations' request returns all possible locations for source breakpoints in a given range.
+type BreakpointLocationsRequest struct {
+	Request
+
+	Arguments BreakpointLocationsArguments `json:"arguments,omitempty"`
+}
+
+// BreakpointLocationsArguments: Arguments for 'breakpointLocations' request.
+type BreakpointLocationsArguments struct {
+	Source    Source `json:"source"`
+	Line      int    `json:"line"`
+	Column    int    `json:"column,omitempty"`
+	EndLine   int    `json:"endLine,omitempty"`
+	EndColumn int    `json:"endColumn,omitempty"`
+}
+
+// BreakpointLocationsResponse: Response to 'breakpointLocations' request.
+// Contains possible locations for source breakpoints.
+type BreakpointLocationsResponse struct {
+	Response
+
+	Body BreakpointLocationsResponseBody `json:"body"`
+}
+
+type BreakpointLocationsResponseBody struct {
+	Breakpoints []BreakpointLocation `json:"breakpoints"`
+}
+
+// SetBreakpointsRequest: Sets multiple breakpoints for a single source and clears all previous breakpoints in that source.
+// To clear all breakpoint for a source, specify an empty array.
+// When a breakpoint is hit, a 'stopped' event (with reason 'breakpoint') is generated.
+type SetBreakpointsRequest struct {
+	Request
+
+	Arguments SetBreakpointsArguments `json:"arguments"`
+}
+
+// SetBreakpointsArguments: Arguments for 'setBreakpoints' request.
+type SetBreakpointsArguments struct {
+	Source         Source             `json:"source"`
+	Breakpoints    []SourceBreakpoint `json:"breakpoints,omitempty"`
+	Lines          []int              `json:"lines,omitempty"`
+	SourceModified bool               `json:"sourceModified,omitempty"`
+}
+
+// SetBreakpointsResponse: Response to 'setBreakpoints' request.
+// Returned is information about each breakpoint created by this request.
+// This includes the actual code location and whether the breakpoint could be verified.
+// The breakpoints returned are in the same order as the elements of the 'breakpoints'
+// (or the deprecated 'lines') array in the arguments.
+type SetBreakpointsResponse struct {
+	Response
+
+	Body SetBreakpointsResponseBody `json:"body"`
+}
+
+type SetBreakpointsResponseBody struct {
+	Breakpoints []Breakpoint `json:"breakpoints"`
+}
+
+// SetFunctionBreakpointsRequest: Replaces all existing function breakpoints with new function breakpoints.
+// To clear all function breakpoints, specify an empty array.
+// When a function breakpoint is hit, a 'stopped' event (with reason 'function breakpoint') is generated.
+type SetFunctionBreakpointsRequest struct {
+	Request
+
+	Arguments SetFunctionBreakpointsArguments `json:"arguments"`
+}
+
+// SetFunctionBreakpointsArguments: Arguments for 'setFunctionBreakpoints' request.
+type SetFunctionBreakpointsArguments struct {
+	Breakpoints []FunctionBreakpoint `json:"breakpoints"`
+}
+
+// SetFunctionBreakpointsResponse: Response to 'setFunctionBreakpoints' request.
+// Returned is information about each breakpoint created by this request.
+type SetFunctionBreakpointsResponse struct {
+	Response
+
+	Body SetFunctionBreakpointsResponseBody `json:"body"`
+}
+
+type SetFunctionBreakpointsResponseBody struct {
+	Breakpoints []Breakpoint `json:"breakpoints"`
+}
+
+// SetExceptionBreakpointsRequest: The request configures the debuggers response to thrown exceptions. If an exception is configured to break, a 'stopped' event is fired (with reason 'exception').
+type SetExceptionBreakpointsRequest struct {
+	Request
+
+	Arguments SetExceptionBreakpointsArguments `json:"arguments"`
+}
+
+// SetExceptionBreakpointsArguments: Arguments for 'setExceptionBreakpoints' request.
+type SetExceptionBreakpointsArguments struct {
+	Filters          []string           `json:"filters"`
+	ExceptionOptions []ExceptionOptions `json:"exceptionOptions,omitempty"`
+}
+
+// SetExceptionBreakpointsResponse: Response to 'setExceptionBreakpoints' request. This is just an acknowledgement, so no body field is required.
+type SetExceptionBreakpointsResponse struct {
+	Response
+}
+
+// DataBreakpointInfoRequest: Obtains information on a possible data breakpoint that could be set on an expression or variable.
+type DataBreakpointInfoRequest struct {
+	Request
+
+	Arguments DataBreakpointInfoArguments `json:"arguments"`
+}
+
+// DataBreakpointInfoArguments: Arguments for 'dataBreakpointInfo' request.
+type DataBreakpointInfoArguments struct {
+	VariablesReference int    `json:"variablesReference,omitempty"`
+	Name               string `json:"name"`
+}
+
+// DataBreakpointInfoResponse: Response to 'dataBreakpointInfo' request.
+type DataBreakpointInfoResponse struct {
+	Response
+
+	Body DataBreakpointInfoResponseBody `json:"body"`
+}
+
+type DataBreakpointInfoResponseBody struct {
+	DataId      interface{}                `json:"dataId"`
+	Description string                     `json:"description"`
+	AccessTypes []DataBreakpointAccessType `json:"accessTypes,omitempty"`
+	CanPersist  bool                       `json:"canPersist,omitempty"`
+}
+
+// SetDataBreakpointsRequest: Replaces all existing data breakpoints with new data breakpoints.
+// To clear all data breakpoints, specify an empty array.
+// When a data breakpoint is hit, a 'stopped' event (with reason 'data breakpoint') is generated.
+type SetDataBreakpointsRequest struct {
+	Request
+
+	Arguments SetDataBreakpointsArguments `json:"arguments"`
+}
+
+// SetDataBreakpointsArguments: Arguments for 'setDataBreakpoints' request.
+type SetDataBreakpointsArguments struct {
+	Breakpoints []DataBreakpoint `json:"breakpoints"`
+}
+
+// SetDataBreakpointsResponse: Response to 'setDataBreakpoints' request.
+// Returned is information about each breakpoint created by this request.
+type SetDataBreakpointsResponse struct {
+	Response
+
+	Body SetDataBreakpointsResponseBody `json:"body"`
+}
+
+type SetDataBreakpointsResponseBody struct {
+	Breakpoints []Breakpoint `json:"breakpoints"`
+}
+
+// ContinueRequest: The request starts the debuggee to run again.
+type ContinueRequest struct {
+	Request
+
+	Arguments ContinueArguments `json:"arguments"`
+}
+
+// ContinueArguments: Arguments for 'continue' request.
+type ContinueArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// ContinueResponse: Response to 'continue' request.
+type ContinueResponse struct {
+	Response
+
+	Body ContinueResponseBody `json:"body"`
+}
+
+type ContinueResponseBody struct {
+	AllThreadsContinued bool `json:"allThreadsContinued,omitempty"`
+}
+
+// NextRequest: The request starts the debuggee to run again for one step.
+// The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
+type NextRequest struct {
+	Request
+
+	Arguments NextArguments `json:"arguments"`
+}
+
+// NextArguments: Arguments for 'next' request.
+type NextArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// NextResponse: Response to 'next' request. This is just an acknowledgement, so no body field is required.
+type NextResponse struct {
+	Response
+}
+
+// StepInRequest: The request starts the debuggee to step into a function/method if possible.
+// If it cannot step into a target, 'stepIn' behaves like 'next'.
+// The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
+// If there are multiple function/method calls (or other targets) on the source line,
+// the optional argument 'targetId' can be used to control into which target the 'stepIn' should occur.
+// The list of possible targets for a given source line can be retrieved via the 'stepInTargets' request.
+type StepInRequest struct {
+	Request
+
+	Arguments StepInArguments `json:"arguments"`
+}
+
+// StepInArguments: Arguments for 'stepIn' request.
+type StepInArguments struct {
+	ThreadId int `json:"threadId"`
+	TargetId int `json:"targetId,omitempty"`
+}
+
+// StepInResponse: Response to 'stepIn' request. This is just an acknowledgement, so no body field is required.
+type StepInResponse struct {
+	Response
+}
+
+// StepOutRequest: The request starts the debuggee to run again for one step.
+// The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed.
+type StepOutRequest struct {
+	Request
+
+	Arguments StepOutArguments `json:"arguments"`
+}
+
+// StepOutArguments: Arguments for 'stepOut' request.
+type StepOutArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// StepOutResponse: Response to 'stepOut' request. This is just an acknowledgement, so no body field is required.
+type StepOutResponse struct {
+	Response
+}
+
+// StepBackRequest: The request starts the debuggee to run one step backwards.
+// The debug adapter first sends the response and then a 'stopped' event (with reason 'step') after the step has completed. Clients should only call this request if the capability 'supportsStepBack' is true.
+type StepBackRequest struct {
+	Request
+
+	Arguments StepBackArguments `json:"arguments"`
+}
+
+// StepBackArguments: Arguments for 'stepBack' request.
+type StepBackArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// StepBackResponse: Response to 'stepBack' request. This is just an acknowledgement, so no body field is required.
+type StepBackResponse struct {
+	Response
+}
+
+// ReverseContinueRequest: The request starts the debuggee to run backward. Clients should only call this request if the capability 'supportsStepBack' is true.
+type ReverseContinueRequest struct {
+	Request
+
+	Arguments ReverseContinueArguments `json:"arguments"`
+}
+
+// ReverseContinueArguments: Arguments for 'reverseContinue' request.
+type ReverseContinueArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// ReverseContinueResponse: Response to 'reverseContinue' request. This is just an acknowledgement, so no body field is required.
+type ReverseContinueResponse struct {
+	Response
+}
+
+// RestartFrameRequest: The request restarts execution of the specified stackframe.
+// The debug adapter first sends the response and then a 'stopped' event (with reason 'restart') after the restart has completed.
+type RestartFrameRequest struct {
+	Request
+
+	Arguments RestartFrameArguments `json:"arguments"`
+}
+
+// RestartFrameArguments: Arguments for 'restartFrame' request.
+type RestartFrameArguments struct {
+	FrameId int `json:"frameId"`
+}
+
+// RestartFrameResponse: Response to 'restartFrame' request. This is just an acknowledgement, so no body field is required.
+type RestartFrameResponse struct {
+	Response
+}
+
+// GotoRequest: The request sets the location where the debuggee will continue to run.
+// This makes it possible to skip the execution of code or to executed code again.
+// The code between the current location and the goto target is not executed but skipped.
+// The debug adapter first sends the response and then a 'stopped' event with reason 'goto'.
+type GotoRequest struct {
+	Request
+
+	Arguments GotoArguments `json:"arguments"`
+}
+
+// GotoArguments: Arguments for 'goto' request.
+type GotoArguments struct {
+	ThreadId int `json:"threadId"`
+	TargetId int `json:"targetId"`
+}
+
+// GotoResponse: Response to 'goto' request. This is just an acknowledgement, so no body field is required.
+type GotoResponse struct {
+	Response
+}
+
+// PauseRequest: The request suspends the debuggee.
+// The debug adapter first sends the response and then a 'stopped' event (with reason 'pause') after the thread has been paused successfully.
+type PauseRequest struct {
+	Request
+
+	Arguments PauseArguments `json:"arguments"`
+}
+
+// PauseArguments: Arguments for 'pause' request.
+type PauseArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// PauseResponse: Response to 'pause' request. This is just an acknowledgement, so no body field is required.
+type PauseResponse struct {
+	Response
+}
+
+// StackTraceRequest: The request returns a stacktrace from the current execution state.
+type StackTraceRequest struct {
+	Request
+
+	Arguments StackTraceArguments `json:"arguments"`
+}
+
+// StackTraceArguments: Arguments for 'stackTrace' request.
+type StackTraceArguments struct {
+	ThreadId   int              `json:"threadId"`
+	StartFrame int              `json:"startFrame,omitempty"`
+	Levels     int              `json:"levels,omitempty"`
+	Format     StackFrameFormat `json:"format,omitempty"`
+}
+
+// StackTraceResponse: Response to 'stackTrace' request.
+type StackTraceResponse struct {
+	Response
+
+	Body StackTraceResponseBody `json:"body"`
+}
+
+type StackTraceResponseBody struct {
+	StackFrames []StackFrame `json:"stackFrames"`
+	TotalFrames int          `json:"totalFrames,omitempty"`
+}
+
+// ScopesRequest: The request returns the variable scopes for a given stackframe ID.
+type ScopesRequest struct {
+	Request
+
+	Arguments ScopesArguments `json:"arguments"`
+}
+
+// ScopesArguments: Arguments for 'scopes' request.
+type ScopesArguments struct {
+	FrameId int `json:"frameId"`
+}
+
+// ScopesResponse: Response to 'scopes' request.
+type ScopesResponse struct {
+	Response
+
+	Body ScopesResponseBody `json:"body"`
+}
+
+type ScopesResponseBody struct {
+	Scopes []Scope `json:"scopes"`
+}
+
+// VariablesRequest: Retrieves all child variables for the given variable reference.
+// An optional filter can be used to limit the fetched children to either named or indexed children.
+type VariablesRequest struct {
+	Request
+
+	Arguments VariablesArguments `json:"arguments"`
+}
+
+// VariablesArguments: Arguments for 'variables' request.
+type VariablesArguments struct {
+	VariablesReference int         `json:"variablesReference"`
+	Filter             string      `json:"filter,omitempty"`
+	Start              int         `json:"start,omitempty"`
+	Count              int         `json:"count,omitempty"`
+	Format             ValueFormat `json:"format,omitempty"`
+}
+
+// VariablesResponse: Response to 'variables' request.
+type VariablesResponse struct {
+	Response
+
+	Body VariablesResponseBody `json:"body"`
+}
+
+type VariablesResponseBody struct {
+	Variables []Variable `json:"variables"`
+}
+
+// SetVariableRequest: Set the variable with the given name in the variable container to a new value.
+type SetVariableRequest struct {
+	Request
+
+	Arguments SetVariableArguments `json:"arguments"`
+}
+
+// SetVariableArguments: Arguments for 'setVariable' request.
+type SetVariableArguments struct {
+	VariablesReference int         `json:"variablesReference"`
+	Name               string      `json:"name"`
+	Value              string      `json:"value"`
+	Format             ValueFormat `json:"format,omitempty"`
+}
+
+// SetVariableResponse: Response to 'setVariable' request.
+type SetVariableResponse struct {
+	Response
+
+	Body SetVariableResponseBody `json:"body"`
+}
+
+type SetVariableResponseBody struct {
+	Value              string `json:"value"`
+	Type               string `json:"type,omitempty"`
+	VariablesReference int    `json:"variablesReference,omitempty"`
+	NamedVariables     int    `json:"namedVariables,omitempty"`
+	IndexedVariables   int    `json:"indexedVariables,omitempty"`
+}
+
+// SourceRequest: The request retrieves the source code for a given source reference.
+type SourceRequest struct {
+	Request
+
+	Arguments SourceArguments `json:"arguments"`
+}
+
+// SourceArguments: Arguments for 'source' request.
+type SourceArguments struct {
+	Source          Source `json:"source,omitempty"`
+	SourceReference int    `json:"sourceReference"`
+}
+
+// SourceResponse: Response to 'source' request.
+type SourceResponse struct {
+	Response
+
+	Body SourceResponseBody `json:"body"`
+}
+
+type SourceResponseBody struct {
+	Content  string `json:"content"`
+	MimeType string `json:"mimeType,omitempty"`
+}
+
+// ThreadsRequest: The request retrieves a list of all threads.
+type ThreadsRequest struct {
+	Request
+}
+
+// ThreadsResponse: Response to 'threads' request.
+type ThreadsResponse struct {
+	Response
+
+	Body ThreadsResponseBody `json:"body"`
+}
+
+type ThreadsResponseBody struct {
+	Threads []Thread `json:"threads"`
+}
+
+// TerminateThreadsRequest: The request terminates the threads with the given ids.
+type TerminateThreadsRequest struct {
+	Request
+
+	Arguments TerminateThreadsArguments `json:"arguments"`
+}
+
+// TerminateThreadsArguments: Arguments for 'terminateThreads' request.
+type TerminateThreadsArguments struct {
+	ThreadIds []int `json:"threadIds,omitempty"`
+}
+
+// TerminateThreadsResponse: Response to 'terminateThreads' request. This is just an acknowledgement, so no body field is required.
+type TerminateThreadsResponse struct {
+	Response
+}
+
+// ModulesRequest: Modules can be retrieved from the debug adapter with the ModulesRequest which can either return all modules or a range of modules to support paging.
+type ModulesRequest struct {
+	Request
+
+	Arguments ModulesArguments `json:"arguments"`
+}
+
+// ModulesArguments: Arguments for 'modules' request.
+type ModulesArguments struct {
+	StartModule int `json:"startModule,omitempty"`
+	ModuleCount int `json:"moduleCount,omitempty"`
+}
+
+// ModulesResponse: Response to 'modules' request.
+type ModulesResponse struct {
+	Response
+
+	Body ModulesResponseBody `json:"body"`
+}
+
+type ModulesResponseBody struct {
+	Modules      []Module `json:"modules"`
+	TotalModules int      `json:"totalModules,omitempty"`
+}
+
+// LoadedSourcesRequest: Retrieves the set of all sources currently loaded by the debugged process.
+type LoadedSourcesRequest struct {
+	Request
+
+	Arguments LoadedSourcesArguments `json:"arguments,omitempty"`
+}
+
+// LoadedSourcesArguments: Arguments for 'loadedSources' request.
+type LoadedSourcesArguments struct {
+}
+
+// LoadedSourcesResponse: Response to 'loadedSources' request.
+type LoadedSourcesResponse struct {
+	Response
+
+	Body LoadedSourcesResponseBody `json:"body"`
+}
+
+type LoadedSourcesResponseBody struct {
+	Sources []Source `json:"sources"`
+}
+
+// EvaluateRequest: Evaluates the given expression in the context of the top most stack frame.
+// The expression has access to any variables and arguments that are in scope.
+type EvaluateRequest struct {
+	Request
+
+	Arguments EvaluateArguments `json:"arguments"`
+}
+
+// EvaluateArguments: Arguments for 'evaluate' request.
+type EvaluateArguments struct {
+	Expression string      `json:"expression"`
+	FrameId    int         `json:"frameId,omitempty"`
+	Context    string      `json:"context,omitempty"`
+	Format     ValueFormat `json:"format,omitempty"`
+}
+
+// EvaluateResponse: Response to 'evaluate' request.
+type EvaluateResponse struct {
+	Response
+
+	Body EvaluateResponseBody `json:"body"`
+}
+
+type EvaluateResponseBody struct {
+	Result             string                   `json:"result"`
+	Type               string                   `json:"type,omitempty"`
+	PresentationHint   VariablePresentationHint `json:"presentationHint,omitempty"`
+	VariablesReference int                      `json:"variablesReference"`
+	NamedVariables     int                      `json:"namedVariables,omitempty"`
+	IndexedVariables   int                      `json:"indexedVariables,omitempty"`
+	MemoryReference    string                   `json:"memoryReference,omitempty"`
+}
+
+// SetExpressionRequest: Evaluates the given 'value' expression and assigns it to the 'expression' which must be a modifiable l-value.
+// The expressions have access to any variables and arguments that are in scope of the specified frame.
+type SetExpressionRequest struct {
+	Request
+
+	Arguments SetExpressionArguments `json:"arguments"`
+}
+
+// SetExpressionArguments: Arguments for 'setExpression' request.
+type SetExpressionArguments struct {
+	Expression string      `json:"expression"`
+	Value      string      `json:"value"`
+	FrameId    int         `json:"frameId,omitempty"`
+	Format     ValueFormat `json:"format,omitempty"`
+}
+
+// SetExpressionResponse: Response to 'setExpression' request.
+type SetExpressionResponse struct {
+	Response
+
+	Body SetExpressionResponseBody `json:"body"`
+}
+
+type SetExpressionResponseBody struct {
+	Value              string                   `json:"value"`
+	Type               string                   `json:"type,omitempty"`
+	PresentationHint   VariablePresentationHint `json:"presentationHint,omitempty"`
+	VariablesReference int                      `json:"variablesReference,omitempty"`
+	NamedVariables     int                      `json:"namedVariables,omitempty"`
+	IndexedVariables   int                      `json:"indexedVariables,omitempty"`
+}
+
+// StepInTargetsRequest: This request retrieves the possible stepIn targets for the specified stack frame.
+// These targets can be used in the 'stepIn' request.
+// The StepInTargets may only be called if the 'supportsStepInTargetsRequest' capability exists and is true.
+type StepInTargetsRequest struct {
+	Request
+
+	Arguments StepInTargetsArguments `json:"arguments"`
+}
+
+// StepInTargetsArguments: Arguments for 'stepInTargets' request.
+type StepInTargetsArguments struct {
+	FrameId int `json:"frameId"`
+}
+
+// StepInTargetsResponse: Response to 'stepInTargets' request.
+type StepInTargetsResponse struct {
+	Response
+
+	Body StepInTargetsResponseBody `json:"body"`
+}
+
+type StepInTargetsResponseBody struct {
+	Targets []StepInTarget `json:"targets"`
+}
+
+// GotoTargetsRequest: This request retrieves the possible goto targets for the specified source location.
+// These targets can be used in the 'goto' request.
+// The GotoTargets request may only be called if the 'supportsGotoTargetsRequest' capability exists and is true.
+type GotoTargetsRequest struct {
+	Request
+
+	Arguments GotoTargetsArguments `json:"arguments"`
+}
+
+// GotoTargetsArguments: Arguments for 'gotoTargets' request.
+type GotoTargetsArguments struct {
+	Source Source `json:"source"`
+	Line   int    `json:"line"`
+	Column int    `json:"column,omitempty"`
+}
+
+// GotoTargetsResponse: Response to 'gotoTargets' request.
+type GotoTargetsResponse struct {
+	Response
+
+	Body GotoTargetsResponseBody `json:"body"`
+}
+
+type GotoTargetsResponseBody struct {
+	Targets []GotoTarget `json:"targets"`
+}
+
+// CompletionsRequest: Returns a list of possible completions for a given caret position and text.
+// The CompletionsRequest may only be called if the 'supportsCompletionsRequest' capability exists and is true.
+type CompletionsRequest struct {
+	Request
+
+	Arguments CompletionsArguments `json:"arguments"`
+}
+
+// CompletionsArguments: Arguments for 'completions' request.
+type CompletionsArguments struct {
+	FrameId int    `json:"frameId,omitempty"`
+	Text    string `json:"text"`
+	Column  int    `json:"column"`
+	Line    int    `json:"line,omitempty"`
+}
+
+// CompletionsResponse: Response to 'completions' request.
+type CompletionsResponse struct {
+	Response
+
+	Body CompletionsResponseBody `json:"body"`
+}
+
+type CompletionsResponseBody struct {
+	Targets []CompletionItem `json:"targets"`
+}
+
+// ExceptionInfoRequest: Retrieves the details of the exception that caused this event to be raised.
+type ExceptionInfoRequest struct {
+	Request
+
+	Arguments ExceptionInfoArguments `json:"arguments"`
+}
+
+// ExceptionInfoArguments: Arguments for 'exceptionInfo' request.
+type ExceptionInfoArguments struct {
+	ThreadId int `json:"threadId"`
+}
+
+// ExceptionInfoResponse: Response to 'exceptionInfo' request.
+type ExceptionInfoResponse struct {
+	Response
+
+	Body ExceptionInfoResponseBody `json:"body"`
+}
+
+type ExceptionInfoResponseBody struct {
+	ExceptionId string             `json:"exceptionId"`
+	Description string             `json:"description,omitempty"`
+	BreakMode   ExceptionBreakMode `json:"breakMode"`
+	Details     ExceptionDetails   `json:"details,omitempty"`
+}
+
+// ReadMemoryRequest: Reads bytes from memory at the provided location.
+type ReadMemoryRequest struct {
+	Request
+
+	Arguments ReadMemoryArguments `json:"arguments"`
+}
+
+// ReadMemoryArguments: Arguments for 'readMemory' request.
+type ReadMemoryArguments struct {
+	MemoryReference string `json:"memoryReference"`
+	Offset          int    `json:"offset,omitempty"`
+	Count           int    `json:"count"`
+}
+
+// ReadMemoryResponse: Response to 'readMemory' request.
+type ReadMemoryResponse struct {
+	Response
+
+	Body ReadMemoryResponseBody `json:"body,omitempty"`
+}
+
+type ReadMemoryResponseBody struct {
+	Address         string `json:"address"`
+	UnreadableBytes int    `json:"unreadableBytes,omitempty"`
+	Data            string `json:"data,omitempty"`
+}
+
+// DisassembleRequest: Disassembles code stored at the provided location.
+type DisassembleRequest struct {
+	Request
+
+	Arguments DisassembleArguments `json:"arguments"`
+}
+
+// DisassembleArguments: Arguments for 'disassemble' request.
+type DisassembleArguments struct {
+	MemoryReference   string `json:"memoryReference"`
+	Offset            int    `json:"offset,omitempty"`
+	InstructionOffset int    `json:"instructionOffset,omitempty"`
+	InstructionCount  int    `json:"instructionCount"`
+	ResolveSymbols    bool   `json:"resolveSymbols,omitempty"`
+}
+
+// DisassembleResponse: Response to 'disassemble' request.
+type DisassembleResponse struct {
+	Response
+
+	Body DisassembleResponseBody `json:"body,omitempty"`
+}
+
+type DisassembleResponseBody struct {
+	Instructions []DisassembledInstruction `json:"instructions"`
+}
+
+// Capabilities: Information about the capabilities of a debug adapter.
+type Capabilities struct {
+	SupportsConfigurationDoneRequest   bool                         `json:"supportsConfigurationDoneRequest,omitempty"`
+	SupportsFunctionBreakpoints        bool                         `json:"supportsFunctionBreakpoints,omitempty"`
+	SupportsConditionalBreakpoints     bool                         `json:"supportsConditionalBreakpoints,omitempty"`
+	SupportsHitConditionalBreakpoints  bool                         `json:"supportsHitConditionalBreakpoints,omitempty"`
+	SupportsEvaluateForHovers          bool                         `json:"supportsEvaluateForHovers,omitempty"`
+	ExceptionBreakpointFilters         []ExceptionBreakpointsFilter `json:"exceptionBreakpointFilters,omitempty"`
+	SupportsStepBack                   bool                         `json:"supportsStepBack,omitempty"`
+	SupportsSetVariable                bool                         `json:"supportsSetVariable,omitempty"`
+	SupportsRestartFrame               bool                         `json:"supportsRestartFrame,omitempty"`
+	SupportsGotoTargetsRequest         bool                         `json:"supportsGotoTargetsRequest,omitempty"`
+	SupportsStepInTargetsRequest       bool                         `json:"supportsStepInTargetsRequest,omitempty"`
+	SupportsCompletionsRequest         bool                         `json:"supportsCompletionsRequest,omitempty"`
+	CompletionTriggerCharacters        []string                     `json:"completionTriggerCharacters,omitempty"`
+	SupportsModulesRequest             bool                         `json:"supportsModulesRequest,omitempty"`
+	AdditionalModuleColumns            []ColumnDescriptor           `json:"additionalModuleColumns,omitempty"`
+	SupportedChecksumAlgorithms        []ChecksumAlgorithm          `json:"supportedChecksumAlgorithms,omitempty"`
+	SupportsRestartRequest             bool                         `json:"supportsRestartRequest,omitempty"`
+	SupportsExceptionOptions           bool                         `json:"supportsExceptionOptions,omitempty"`
+	SupportsValueFormattingOptions     bool                         `json:"supportsValueFormattingOptions,omitempty"`
+	SupportsExceptionInfoRequest       bool                         `json:"supportsExceptionInfoRequest,omitempty"`
+	SupportTerminateDebuggee           bool                         `json:"supportTerminateDebuggee,omitempty"`
+	SupportsDelayedStackTraceLoading   bool                         `json:"supportsDelayedStackTraceLoading,omitempty"`
+	SupportsLoadedSourcesRequest       bool                         `json:"supportsLoadedSourcesRequest,omitempty"`
+	SupportsLogPoints                  bool                         `json:"supportsLogPoints,omitempty"`
+	SupportsTerminateThreadsRequest    bool                         `json:"supportsTerminateThreadsRequest,omitempty"`
+	SupportsSetExpression              bool                         `json:"supportsSetExpression,omitempty"`
+	SupportsTerminateRequest           bool                         `json:"supportsTerminateRequest,omitempty"`
+	SupportsDataBreakpoints            bool                         `json:"supportsDataBreakpoints,omitempty"`
+	SupportsReadMemoryRequest          bool                         `json:"supportsReadMemoryRequest,omitempty"`
+	SupportsDisassembleRequest         bool                         `json:"supportsDisassembleRequest,omitempty"`
+	SupportsCancelRequest              bool                         `json:"supportsCancelRequest,omitempty"`
+	SupportsBreakpointLocationsRequest bool                         `json:"supportsBreakpointLocationsRequest,omitempty"`
+}
+
+// ExceptionBreakpointsFilter: An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with.
+type ExceptionBreakpointsFilter struct {
+	Filter  string `json:"filter"`
+	Label   string `json:"label"`
+	Default bool   `json:"default,omitempty"`
+}
+
+// ErrorMessage: A structured message object. Used to return errors from requests.
+type ErrorMessage struct {
+	Id            int               `json:"id"`
+	Format        string            `json:"format"`
+	Variables     map[string]string `json:"variables,omitempty"`
+	SendTelemetry bool              `json:"sendTelemetry,omitempty"`
+	ShowUser      bool              `json:"showUser,omitempty"`
+	Url           string            `json:"url,omitempty"`
+	UrlLabel      string            `json:"urlLabel,omitempty"`
+}
+
+// Module: A Module object represents a row in the modules view.
+// Two attributes are mandatory: an id identifies a module in the modules view and is used in a ModuleEvent for identifying a module for adding, updating or deleting.
+// The name is used to minimally render the module in the UI.
+//
+// Additional attributes can be added to the module. They will show up in the module View if they have a corresponding ColumnDescriptor.
+//
+// To avoid an unnecessary proliferation of additional attributes with similar semantics but different names
+// we recommend to re-use attributes from the 'recommended' list below first, and only introduce new attributes if nothing appropriate could be found.
+type Module struct {
+	Id             interface{} `json:"id"`
+	Name           string      `json:"name"`
+	Path           string      `json:"path,omitempty"`
+	IsOptimized    bool        `json:"isOptimized,omitempty"`
+	IsUserCode     bool        `json:"isUserCode,omitempty"`
+	Version        string      `json:"version,omitempty"`
+	SymbolStatus   string      `json:"symbolStatus,omitempty"`
+	SymbolFilePath string      `json:"symbolFilePath,omitempty"`
+	DateTimeStamp  string      `json:"dateTimeStamp,omitempty"`
+	AddressRange   string      `json:"addressRange,omitempty"`
+}
+
+// ColumnDescriptor: A ColumnDescriptor specifies what module attribute to show in a column of the ModulesView, how to format it, and what the column's label should be.
+// It is only used if the underlying UI actually supports this level of customization.
+type ColumnDescriptor struct {
+	AttributeName string `json:"attributeName"`
+	Label         string `json:"label"`
+	Format        string `json:"format,omitempty"`
+	Type          string `json:"type,omitempty"`
+	Width         int    `json:"width,omitempty"`
+}
+
+// ModulesViewDescriptor: The ModulesViewDescriptor is the container for all declarative configuration options of a ModuleView.
+// For now it only specifies the columns to be shown in the modules view.
+type ModulesViewDescriptor struct {
+	Columns []ColumnDescriptor `json:"columns"`
+}
+
+// Thread: A Thread
+type Thread struct {
+	Id   int    `json:"id"`
+	Name string `json:"name"`
+}
+
+// Source: A Source is a descriptor for source code. It is returned from the debug adapter as part of a StackFrame and it is used by clients when specifying breakpoints.
+type Source struct {
+	Name             string      `json:"name,omitempty"`
+	Path             string      `json:"path,omitempty"`
+	SourceReference  int         `json:"sourceReference,omitempty"`
+	PresentationHint string      `json:"presentationHint,omitempty"`
+	Origin           string      `json:"origin,omitempty"`
+	Sources          []Source    `json:"sources,omitempty"`
+	AdapterData      interface{} `json:"adapterData,omitempty"`
+	Checksums        []Checksum  `json:"checksums,omitempty"`
+}
+
+// StackFrame: A Stackframe contains the source location.
+type StackFrame struct {
+	Id                          int         `json:"id"`
+	Name                        string      `json:"name"`
+	Source                      Source      `json:"source,omitempty"`
+	Line                        int         `json:"line"`
+	Column                      int         `json:"column"`
+	EndLine                     int         `json:"endLine,omitempty"`
+	EndColumn                   int         `json:"endColumn,omitempty"`
+	InstructionPointerReference string      `json:"instructionPointerReference,omitempty"`
+	ModuleId                    interface{} `json:"moduleId,omitempty"`
+	PresentationHint            string      `json:"presentationHint,omitempty"`
+}
+
+// Scope: A Scope is a named container for variables. Optionally a scope can map to a source or a range within a source.
+type Scope struct {
+	Name               string `json:"name"`
+	PresentationHint   string `json:"presentationHint,omitempty"`
+	VariablesReference int    `json:"variablesReference"`
+	NamedVariables     int    `json:"namedVariables,omitempty"`
+	IndexedVariables   int    `json:"indexedVariables,omitempty"`
+	Expensive          bool   `json:"expensive"`
+	Source             Source `json:"source,omitempty"`
+	Line               int    `json:"line,omitempty"`
+	Column             int    `json:"column,omitempty"`
+	EndLine            int    `json:"endLine,omitempty"`
+	EndColumn          int    `json:"endColumn,omitempty"`
+}
+
+// Variable: A Variable is a name/value pair.
+// Optionally a variable can have a 'type' that is shown if space permits or when hovering over the variable's name.
+// An optional 'kind' is used to render additional properties of the variable, e.g. different icons can be used to indicate that a variable is public or private.
+// If the value is structured (has children), a handle is provided to retrieve the children with the VariablesRequest.
+// If the number of named or indexed children is large, the numbers should be returned via the optional 'namedVariables' and 'indexedVariables' attributes.
+// The client can use this optional information to present the children in a paged UI and fetch them in chunks.
+type Variable struct {
+	Name               string                   `json:"name"`
+	Value              string                   `json:"value"`
+	Type               string                   `json:"type,omitempty"`
+	PresentationHint   VariablePresentationHint `json:"presentationHint,omitempty"`
+	EvaluateName       string                   `json:"evaluateName,omitempty"`
+	VariablesReference int                      `json:"variablesReference"`
+	NamedVariables     int                      `json:"namedVariables,omitempty"`
+	IndexedVariables   int                      `json:"indexedVariables,omitempty"`
+	MemoryReference    string                   `json:"memoryReference,omitempty"`
+}
+
+// VariablePresentationHint: Optional properties of a variable that can be used to determine how to render the variable in the UI.
+type VariablePresentationHint struct {
+	Kind       string   `json:"kind,omitempty"`
+	Attributes []string `json:"attributes,omitempty"`
+	Visibility string   `json:"visibility,omitempty"`
+}
+
+// BreakpointLocation: Properties of a breakpoint location returned from the 'breakpointLocations' request.
+type BreakpointLocation struct {
+	Line      int `json:"line"`
+	Column    int `json:"column,omitempty"`
+	EndLine   int `json:"endLine,omitempty"`
+	EndColumn int `json:"endColumn,omitempty"`
+}
+
+// SourceBreakpoint: Properties of a breakpoint or logpoint passed to the setBreakpoints request.
+type SourceBreakpoint struct {
+	Line         int    `json:"line"`
+	Column       int    `json:"column,omitempty"`
+	Condition    string `json:"condition,omitempty"`
+	HitCondition string `json:"hitCondition,omitempty"`
+	LogMessage   string `json:"logMessage,omitempty"`
+}
+
+// FunctionBreakpoint: Properties of a breakpoint passed to the setFunctionBreakpoints request.
+type FunctionBreakpoint struct {
+	Name         string `json:"name"`
+	Condition    string `json:"condition,omitempty"`
+	HitCondition string `json:"hitCondition,omitempty"`
+}
+
+// DataBreakpointAccessType: This enumeration defines all possible access types for data breakpoints.
+type DataBreakpointAccessType string
+
+// DataBreakpoint: Properties of a data breakpoint passed to the setDataBreakpoints request.
+type DataBreakpoint struct {
+	DataId       string                   `json:"dataId"`
+	AccessType   DataBreakpointAccessType `json:"accessType,omitempty"`
+	Condition    string                   `json:"condition,omitempty"`
+	HitCondition string                   `json:"hitCondition,omitempty"`
+}
+
+// Breakpoint: Information about a Breakpoint created in setBreakpoints or setFunctionBreakpoints.
+type Breakpoint struct {
+	Id        int    `json:"id,omitempty"`
+	Verified  bool   `json:"verified"`
+	Message   string `json:"message,omitempty"`
+	Source    Source `json:"source,omitempty"`
+	Line      int    `json:"line,omitempty"`
+	Column    int    `json:"column,omitempty"`
+	EndLine   int    `json:"endLine,omitempty"`
+	EndColumn int    `json:"endColumn,omitempty"`
+}
+
+// StepInTarget: A StepInTarget can be used in the 'stepIn' request and determines into which single target the stepIn request should step.
+type StepInTarget struct {
+	Id    int    `json:"id"`
+	Label string `json:"label"`
+}
+
+// GotoTarget: A GotoTarget describes a code location that can be used as a target in the 'goto' request.
+// The possible goto targets can be determined via the 'gotoTargets' request.
+type GotoTarget struct {
+	Id                          int    `json:"id"`
+	Label                       string `json:"label"`
+	Line                        int    `json:"line"`
+	Column                      int    `json:"column,omitempty"`
+	EndLine                     int    `json:"endLine,omitempty"`
+	EndColumn                   int    `json:"endColumn,omitempty"`
+	InstructionPointerReference string `json:"instructionPointerReference,omitempty"`
+}
+
+// CompletionItem: CompletionItems are the suggestions returned from the CompletionsRequest.
+type CompletionItem struct {
+	Label    string             `json:"label"`
+	Text     string             `json:"text,omitempty"`
+	SortText string             `json:"sortText,omitempty"`
+	Type     CompletionItemType `json:"type,omitempty"`
+	Start    int                `json:"start,omitempty"`
+	Length   int                `json:"length,omitempty"`
+}
+
+// CompletionItemType: Some predefined types for the CompletionItem. Please note that not all clients have specific icons for all of them.
+type CompletionItemType string
+
+// ChecksumAlgorithm: Names of checksum algorithms that may be supported by a debug adapter.
+type ChecksumAlgorithm string
+
+// Checksum: The checksum of an item calculated by the specified algorithm.
+type Checksum struct {
+	Algorithm ChecksumAlgorithm `json:"algorithm"`
+	Checksum  string            `json:"checksum"`
+}
+
+// ValueFormat: Provides formatting information for a value.
+type ValueFormat struct {
+	Hex bool `json:"hex,omitempty"`
+}
+
+// StackFrameFormat: Provides formatting information for a stack frame.
+type StackFrameFormat struct {
+	ValueFormat
+
+	Parameters      bool `json:"parameters,omitempty"`
+	ParameterTypes  bool `json:"parameterTypes,omitempty"`
+	ParameterNames  bool `json:"parameterNames,omitempty"`
+	ParameterValues bool `json:"parameterValues,omitempty"`
+	Line            bool `json:"line,omitempty"`
+	Module          bool `json:"module,omitempty"`
+	IncludeAll      bool `json:"includeAll,omitempty"`
+}
+
+// ExceptionOptions: An ExceptionOptions assigns configuration options to a set of exceptions.
+type ExceptionOptions struct {
+	Path      []ExceptionPathSegment `json:"path,omitempty"`
+	BreakMode ExceptionBreakMode     `json:"breakMode"`
+}
+
+// ExceptionBreakMode: This enumeration defines all possible conditions when a thrown exception should result in a break.
+// never: never breaks,
+// always: always breaks,
+// unhandled: breaks when exception unhandled,
+// userUnhandled: breaks if the exception is not handled by user code.
+type ExceptionBreakMode string
+
+// ExceptionPathSegment: An ExceptionPathSegment represents a segment in a path that is used to match leafs or nodes in a tree of exceptions. If a segment consists of more than one name, it matches the names provided if 'negate' is false or missing or it matches anything except the names provided if 'negate' is true.
+type ExceptionPathSegment struct {
+	Negate bool     `json:"negate,omitempty"`
+	Names  []string `json:"names"`
+}
+
+// ExceptionDetails: Detailed information about an exception that has occurred.
+type ExceptionDetails struct {
+	Message        string             `json:"message,omitempty"`
+	TypeName       string             `json:"typeName,omitempty"`
+	FullTypeName   string             `json:"fullTypeName,omitempty"`
+	EvaluateName   string             `json:"evaluateName,omitempty"`
+	StackTrace     string             `json:"stackTrace,omitempty"`
+	InnerException []ExceptionDetails `json:"innerException,omitempty"`
+}
+
+// DisassembledInstruction: Represents a single disassembled instruction.
+type DisassembledInstruction struct {
+	Address          string `json:"address"`
+	InstructionBytes string `json:"instructionBytes,omitempty"`
+	Instruction      string `json:"instruction"`
+	Symbol           string `json:"symbol,omitempty"`
+	Location         Source `json:"location,omitempty"`
+	Line             int    `json:"line,omitempty"`
+	Column           int    `json:"column,omitempty"`
+	EndLine          int    `json:"endLine,omitempty"`
+	EndColumn        int    `json:"endColumn,omitempty"`
+}
+
+func (*ProtocolMessage) isMessage()                 {}
+func (*Request) isMessage()                         {}
+func (*Event) isMessage()                           {}
+func (*Response) isMessage()                        {}
+func (*ErrorResponse) isMessage()                   {}
+func (*CancelRequest) isMessage()                   {}
+func (*CancelResponse) isMessage()                  {}
+func (*InitializedEvent) isMessage()                {}
+func (*StoppedEvent) isMessage()                    {}
+func (*ContinuedEvent) isMessage()                  {}
+func (*ExitedEvent) isMessage()                     {}
+func (*TerminatedEvent) isMessage()                 {}
+func (*ThreadEvent) isMessage()                     {}
+func (*OutputEvent) isMessage()                     {}
+func (*BreakpointEvent) isMessage()                 {}
+func (*ModuleEvent) isMessage()                     {}
+func (*LoadedSourceEvent) isMessage()               {}
+func (*ProcessEvent) isMessage()                    {}
+func (*CapabilitiesEvent) isMessage()               {}
+func (*RunInTerminalRequest) isMessage()            {}
+func (*RunInTerminalResponse) isMessage()           {}
+func (*InitializeRequest) isMessage()               {}
+func (*InitializeResponse) isMessage()              {}
+func (*ConfigurationDoneRequest) isMessage()        {}
+func (*ConfigurationDoneResponse) isMessage()       {}
+func (*LaunchRequest) isMessage()                   {}
+func (*LaunchResponse) isMessage()                  {}
+func (*AttachRequest) isMessage()                   {}
+func (*AttachResponse) isMessage()                  {}
+func (*RestartRequest) isMessage()                  {}
+func (*RestartResponse) isMessage()                 {}
+func (*DisconnectRequest) isMessage()               {}
+func (*DisconnectResponse) isMessage()              {}
+func (*TerminateRequest) isMessage()                {}
+func (*TerminateResponse) isMessage()               {}
+func (*BreakpointLocationsRequest) isMessage()      {}
+func (*BreakpointLocationsResponse) isMessage()     {}
+func (*SetBreakpointsRequest) isMessage()           {}
+func (*SetBreakpointsResponse) isMessage()          {}
+func (*SetFunctionBreakpointsRequest) isMessage()   {}
+func (*SetFunctionBreakpointsResponse) isMessage()  {}
+func (*SetExceptionBreakpointsRequest) isMessage()  {}
+func (*SetExceptionBreakpointsResponse) isMessage() {}
+func (*DataBreakpointInfoRequest) isMessage()       {}
+func (*DataBreakpointInfoResponse) isMessage()      {}
+func (*SetDataBreakpointsRequest) isMessage()       {}
+func (*SetDataBreakpointsResponse) isMessage()      {}
+func (*ContinueRequest) isMessage()                 {}
+func (*ContinueResponse) isMessage()                {}
+func (*NextRequest) isMessage()                     {}
+func (*NextResponse) isMessage()                    {}
+func (*StepInRequest) isMessage()                   {}
+func (*StepInResponse) isMessage()                  {}
+func (*StepOutRequest) isMessage()                  {}
+func (*StepOutResponse) isMessage()                 {}
+func (*StepBackRequest) isMessage()                 {}
+func (*StepBackResponse) isMessage()                {}
+func (*ReverseContinueRequest) isMessage()          {}
+func (*ReverseContinueResponse) isMessage()         {}
+func (*RestartFrameRequest) isMessage()             {}
+func (*RestartFrameResponse) isMessage()            {}
+func (*GotoRequest) isMessage()                     {}
+func (*GotoResponse) isMessage()                    {}
+func (*PauseRequest) isMessage()                    {}
+func (*PauseResponse) isMessage()                   {}
+func (*StackTraceRequest) isMessage()               {}
+func (*StackTraceResponse) isMessage()              {}
+func (*ScopesRequest) isMessage()                   {}
+func (*ScopesResponse) isMessage()                  {}
+func (*VariablesRequest) isMessage()                {}
+func (*VariablesResponse) isMessage()               {}
+func (*SetVariableRequest) isMessage()              {}
+func (*SetVariableResponse) isMessage()             {}
+func (*SourceRequest) isMessage()                   {}
+func (*SourceResponse) isMessage()                  {}
+func (*ThreadsRequest) isMessage()                  {}
+func (*ThreadsResponse) isMessage()                 {}
+func (*TerminateThreadsRequest) isMessage()         {}
+func (*TerminateThreadsResponse) isMessage()        {}
+func (*ModulesRequest) isMessage()                  {}
+func (*ModulesResponse) isMessage()                 {}
+func (*LoadedSourcesRequest) isMessage()            {}
+func (*LoadedSourcesResponse) isMessage()           {}
+func (*EvaluateRequest) isMessage()                 {}
+func (*EvaluateResponse) isMessage()                {}
+func (*SetExpressionRequest) isMessage()            {}
+func (*SetExpressionResponse) isMessage()           {}
+func (*StepInTargetsRequest) isMessage()            {}
+func (*StepInTargetsResponse) isMessage()           {}
+func (*GotoTargetsRequest) isMessage()              {}
+func (*GotoTargetsResponse) isMessage()             {}
+func (*CompletionsRequest) isMessage()              {}
+func (*CompletionsResponse) isMessage()             {}
+func (*ExceptionInfoRequest) isMessage()            {}
+func (*ExceptionInfoResponse) isMessage()           {}
+func (*ReadMemoryRequest) isMessage()               {}
+func (*ReadMemoryResponse) isMessage()              {}
+func (*DisassembleRequest) isMessage()              {}
+func (*DisassembleResponse) isMessage()             {}


Test patch:
diff --git a/pkg/proc/core/core_test.go b/pkg/proc/core/core_test.go
index b5752043..9e6be602 100644
--- a/pkg/proc/core/core_test.go
+++ b/pkg/proc/core/core_test.go
@@ -244,8 +244,9 @@ func TestCore(t *testing.T) {
 		t.Fatalf("Couldn't get current thread registers: %v", err)
 	}
 	regslice := regs.Slice(true)
+	arch := p.BinInfo().Arch
 	for _, reg := range regslice {
-		t.Logf("%s = %s", reg.Name, reg.Value)
+		t.Logf("%s = %s", reg.Name, arch.DwarfRegisterToString(reg.Name, reg.Reg))
 	}
 }
 
@@ -312,8 +313,9 @@ func TestCoreFpRegisters(t *testing.T) {
 		{"XMM8", "0x4059999a404ccccd4059999a404ccccd"},
 	}
 
+	arch := p.BinInfo().Arch
 	for _, reg := range regs.Slice(true) {
-		t.Logf("%s = %s", reg.Name, reg.Value)
+		t.Logf("%s = %s", reg.Name, arch.DwarfRegisterToString(reg.Name, reg.Reg))
 	}
 
 	for _, regtest := range regtests {
@@ -321,8 +323,9 @@ func TestCoreFpRegisters(t *testing.T) {
 		for _, reg := range regs.Slice(true) {
 			if reg.Name == regtest.name {
 				found = true
-				if !strings.HasPrefix(reg.Value, regtest.value) {
-					t.Fatalf("register %s expected %q got %q", reg.Name, regtest.value, reg.Value)
+				regval := arch.DwarfRegisterToString(reg.Name, reg.Reg)
+				if !strings.HasPrefix(regval, regtest.value) {
+					t.Fatalf("register %s expected %q got %q", reg.Name, regtest.value, regval)
 				}
 			}
 		}
diff --git a/pkg/terminal/command_test.go b/pkg/terminal/command_test.go
index 0c1df4ab..2f74d904 100644
--- a/pkg/terminal/command_test.go
+++ b/pkg/terminal/command_test.go
@@ -993,3 +993,42 @@ func TestIssue1598(t *testing.T) {
 		}
 	})
 }
+
+func TestExamineMemoryCmd(t *testing.T) {
+	withTestTerminal("examinememory", t, func(term *FakeTerminal) {
+		term.MustExec("break examinememory.go:19")
+		term.MustExec("break examinememory.go:24")
+		term.MustExec("continue")
+
+		addressStr := strings.TrimSpace(term.MustExec("p bspUintptr"))
+		address, err := strconv.ParseInt(addressStr, 0, 64)
+		if err != nil {
+			t.Fatalf("could convert %s into int64, err %s", addressStr, err)
+		}
+
+		res := term.MustExec("examinemem  -len 52 -fmt hex " + addressStr)
+		t.Logf("the result of examining memory \n%s", res)
+		// check first line
+		firstLine := fmt.Sprintf("%#x:    0xa     0xb     0xc     0xd     0xe     0xf     0x10    0x11", address)
+		if !strings.Contains(res, firstLine) {
+			t.Fatalf("expected first line: %s", firstLine)
+		}
+
+		// check last line
+		lastLine := fmt.Sprintf("%#x:    0x3a    0x3b    0x3c    0x0", address+6*8)
+		if !strings.Contains(res, lastLine) {
+			t.Fatalf("expected last line: %s", lastLine)
+		}
+
+		// second examining memory
+		term.MustExec("continue")
+		res = term.MustExec("x -len 52 -fmt bin " + addressStr)
+		t.Logf("the second result of examining memory result \n%s", res)
+
+		// check first line
+		firstLine = fmt.Sprintf("%#x:    11111111    00001011    00001100    00001101", address)
+		if !strings.Contains(res, firstLine) {
+			t.Fatalf("expected first line: %s", firstLine)
+		}
+	})
+}
diff --git a/service/dap/daptest/client.go b/service/dap/daptest/client.go
new file mode 100644
index 00000000..90f77ec7
--- /dev/null
+++ b/service/dap/daptest/client.go
@@ -0,0 +1,189 @@
+package daptest
+
+import (
+	"bufio"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"net"
+	"path/filepath"
+
+	"github.com/google/go-dap"
+)
+
+// Package daptest provides a sample client with utilities
+// for DAP mode testing.
+
+// Client is a debugger service client that uses Debug Adaptor Protocol.
+// It does not (yet?) implement service.Client interface.
+// All client methods are synchronous.
+type Client struct {
+	conn   net.Conn
+	reader *bufio.Reader
+	// seq is used to track the sequence number of each
+	// requests that the client sends to the server
+	seq int
+}
+
+// NewClient creates a new Client over a TCP connection.
+// Call Close() to close the connection.
+func NewClient(addr string) *Client {
+	fmt.Println("Connecting to server at:", addr)
+	conn, err := net.Dial("tcp", addr)
+	if err != nil {
+		log.Fatal("dialing:", err)
+	}
+	c := &Client{conn: conn, reader: bufio.NewReader(conn)}
+	return c
+}
+
+// Close closes the client connection
+func (c *Client) Close() {
+	c.conn.Close()
+}
+
+func (c *Client) send(request dap.Message) {
+	jsonmsg, _ := json.Marshal(request)
+	fmt.Println("[client -> server]", string(jsonmsg))
+	dap.WriteProtocolMessage(c.conn, request)
+}
+
+// ReadBaseMessage reads and returns a json-encoded DAP message.
+func (c *Client) ReadBaseMessage() ([]byte, error) {
+	message, err := dap.ReadBaseMessage(c.reader)
+	if err != nil {
+		fmt.Println("DAP client error:", err)
+		return nil, err
+	}
+	fmt.Println("[client <- server]", string(message))
+	return message, nil
+}
+
+// ReadErrorResponse reads, decodes and validates the result
+// to be an error response. Returns the response or an error.
+func (c *Client) ReadErrorResponse() (dap.Message, error) {
+	response, err := dap.ReadProtocolMessage(c.reader)
+	if err != nil {
+		return nil, err
+	}
+	switch response.(type) {
+	case *dap.ErrorResponse:
+		return response, nil
+	default:
+		return nil, errors.New(fmt.Sprintf("not an ErrorResponse: %#v", response))
+	}
+}
+
+// InitializeRequest sends an 'initialize' request.
+func (c *Client) InitializeRequest() {
+	request := &dap.InitializeRequest{Request: *c.newRequest("initialize")}
+	request.Arguments = dap.InitializeRequestArguments{
+		AdapterID:                    "go",
+		PathFormat:                   "path",
+		LinesStartAt1:                true,
+		ColumnsStartAt1:              true,
+		SupportsVariableType:         true,
+		SupportsVariablePaging:       true,
+		SupportsRunInTerminalRequest: true,
+		Locale:                       "en-us",
+	}
+	c.send(request)
+}
+
+// LaunchRequest sends a 'launch' request.
+func (c *Client) LaunchRequest(program string, stopOnEntry bool) {
+	request := &dap.LaunchRequest{Request: *c.newRequest("launch")}
+	request.Arguments = map[string]interface{}{
+		"request":     "launch",
+		"mode":        "exec",
+		"program":     program,
+		"stopOnEntry": stopOnEntry,
+	}
+	c.send(request)
+}
+
+// DisconnectRequest sends a 'disconnect' request.
+func (c *Client) DisconnectRequest() {
+	request := &dap.DisconnectRequest{Request: *c.newRequest("disconnect")}
+	c.send(request)
+}
+
+// SetBreakpointsRequest sends a 'setBreakpoints' request.
+func (c *Client) SetBreakpointsRequest(file string, lines []int) {
+	request := &dap.SetBreakpointsRequest{Request: *c.newRequest("setBreakpoints")}
+	request.Arguments = dap.SetBreakpointsArguments{
+		Source: dap.Source{
+			Name: filepath.Base(file),
+			Path: file,
+		},
+		Breakpoints: make([]dap.SourceBreakpoint, len(lines)),
+		//sourceModified: false,
+	}
+	for i, l := range lines {
+		request.Arguments.Breakpoints[i].Line = l
+	}
+	c.send(request)
+}
+
+// SetExceptionBreakpointsRequest sends a 'setExceptionBreakpoints' request.
+func (c *Client) SetExceptionBreakpointsRequest() {
+	request := &dap.SetBreakpointsRequest{Request: *c.newRequest("setExceptionBreakpoints")}
+	c.send(request)
+}
+
+// ConfigurationDoneRequest sends a 'configurationDone' request.
+func (c *Client) ConfigurationDoneRequest() {
+	request := &dap.ConfigurationDoneRequest{Request: *c.newRequest("configurationDone")}
+	c.send(request)
+}
+
+// ContinueRequest sends a 'continue' request.
+func (c *Client) ContinueRequest(thread int) {
+	request := &dap.ContinueRequest{Request: *c.newRequest("continue")}
+	request.Arguments.ThreadId = thread
+	c.send(request)
+}
+
+// UnknownRequest triggers dap.DecodeProtocolMessageFieldError.
+func (c *Client) UnkownRequest() {
+	request := c.newRequest("unknown")
+	c.send(request)
+}
+
+// UnkownProtocolMessage triggers dap.DecodeProtocolMessageFieldError.
+func (c *Client) UnkownProtocolMessage() {
+	m := &dap.ProtocolMessage{}
+	m.Seq = -1
+	m.Type = "unknown"
+	c.send(m)
+}
+
+// UnknownEvent triggers dap.DecodeProtocolMessageFieldError.
+func (c *Client) UnknownEvent() {
+	event := &dap.Event{}
+	event.Type = "event"
+	event.Seq = -1
+	event.Event = "unknown"
+	c.send(event)
+}
+
+// KnownEvent passes decode checks, but delve has no 'case' to
+// handle it. This behaves the same way a new request type
+// added to go-dap, but not to delve.
+func (c *Client) KnownEvent() {
+	event := &dap.Event{}
+	event.Type = "event"
+	event.Seq = -1
+	event.Event = "terminated"
+	c.send(event)
+}
+
+func (c *Client) newRequest(command string) *dap.Request {
+	request := &dap.Request{}
+	request.Type = "request"
+	request.Command = command
+	request.Seq = c.seq
+	c.seq++
+	return request
+}
diff --git a/service/dap/server_test.go b/service/dap/server_test.go
new file mode 100644
index 00000000..8b788b01
--- /dev/null
+++ b/service/dap/server_test.go
@@ -0,0 +1,160 @@
+package dap
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"net"
+	"os"
+	"testing"
+	"time"
+
+	"github.com/go-delve/delve/pkg/logflags"
+	protest "github.com/go-delve/delve/pkg/proc/test"
+	"github.com/go-delve/delve/service"
+	"github.com/go-delve/delve/service/dap/daptest"
+	"github.com/google/go-dap"
+)
+
+func TestMain(m *testing.M) {
+	var logOutput string
+	flag.StringVar(&logOutput, "log-output", "", "configures log output")
+	flag.Parse()
+	logflags.Setup(logOutput != "", logOutput, "")
+	os.Exit(protest.RunTestsWithFixtures(m))
+}
+
+func startDAPServer(t *testing.T) (server *Server, addr string) {
+	listener, err := net.Listen("tcp", ":0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	server = NewServer(&service.Config{
+		Listener:       listener,
+		Backend:        "default",
+		DisconnectChan: nil,
+	})
+	server.Run()
+	// Give server time to start listening for clients
+	time.Sleep(100 * time.Millisecond)
+	return server, listener.Addr().String()
+}
+
+func expectMessage(t *testing.T, client *daptest.Client, want []byte) {
+	got, err := client.ReadBaseMessage()
+	if err != nil {
+		t.Error(err)
+	}
+	if !bytes.Equal(got, want) {
+		t.Errorf("\ngot  %q\nwant %q", got, want)
+	}
+}
+
+// name is for _fixtures/<name>.go
+func runTest(t *testing.T, name string, test func(c *daptest.Client, f protest.Fixture)) {
+	var buildFlags protest.BuildFlags
+	fixture := protest.BuildFixture(name, buildFlags)
+
+	server, addr := startDAPServer(t)
+	client := daptest.NewClient(addr)
+	defer client.Close()
+	defer server.Stop()
+
+	test(client, fixture)
+}
+
+// TODO(polina): instead of hardcoding message bytes,
+// add methods to client to receive, decode and verify responses.
+
+func TestStopOnEntry(t *testing.T) {
+	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
+		client.InitializeRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":0,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true}}`))
+
+		client.LaunchRequest(fixture.Path, true /*stopOnEntry*/)
+		expectMessage(t, client, []byte(`{"seq":0,"type":"event","event":"initialized"}`))
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":1,"success":true,"command":"launch"}`))
+
+		client.SetExceptionBreakpointsRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":2,"success":true,"command":"setExceptionBreakpoints"}`))
+
+		client.ConfigurationDoneRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"event","event":"stopped","body":{"reason":"breakpoint","threadId":1,"allThreadsStopped":true}}`))
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":3,"success":true,"command":"configurationDone"}`))
+
+		client.ContinueRequest(1)
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":4,"success":true,"command":"continue","body":{}}`))
+		expectMessage(t, client, []byte(`{"seq":0,"type":"event","event":"terminated","body":{}}`))
+
+		client.DisconnectRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":5,"success":true,"command":"disconnect"}`))
+	})
+}
+
+func TestSetBreakpoint(t *testing.T) {
+	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
+		client.InitializeRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":0,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true}}`))
+
+		client.LaunchRequest(fixture.Path, false /*stopOnEntry*/)
+		expectMessage(t, client, []byte(`{"seq":0,"type":"event","event":"initialized"}`))
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":1,"success":true,"command":"launch"}`))
+
+		client.SetBreakpointsRequest(fixture.Source, []int{8, 100})
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":2,"success":true,"command":"setBreakpoints","body":{"breakpoints":[{"verified":true,"source":{},"line":8}]}}`))
+
+		client.SetExceptionBreakpointsRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":3,"success":true,"command":"setExceptionBreakpoints"}`))
+
+		client.ConfigurationDoneRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":4,"success":true,"command":"configurationDone"}`))
+
+		client.ContinueRequest(1)
+		expectMessage(t, client, []byte(`{"seq":0,"type":"event","event":"stopped","body":{"reason":"breakpoint","threadId":1,"allThreadsStopped":true}}`))
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":5,"success":true,"command":"continue","body":{}}`))
+
+		client.ContinueRequest(1)
+		expectMessage(t, client, []byte(`{"seq":0,"type":"event","event":"terminated","body":{}}`))
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":6,"success":true,"command":"continue","body":{}}`))
+
+		client.DisconnectRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":7,"success":true,"command":"disconnect"}`))
+	})
+}
+
+func expectErrorResponse(t *testing.T, client *daptest.Client, requestSeq int, command string, message string, id int) *dap.ErrorResponse {
+	response, err := client.ReadErrorResponse()
+	if err != nil {
+		t.Error(err)
+		return nil
+	}
+	got := response.(*dap.ErrorResponse)
+	if got.RequestSeq != requestSeq || got.Command != command || got.Message != message || got.Body.Error.Id != id {
+		want := fmt.Sprintf("{RequestSeq: %d, Command: %q, Message: %q, Id: %d}", requestSeq, command, message, id)
+		t.Errorf("\ngot  %#v\nwant %s", got, want)
+		return nil
+	}
+	return got
+}
+
+func TestBadLaunchRequests(t *testing.T) {
+	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
+		client.LaunchRequest("", true)
+		// Test for the DAP-specific detailed error message.
+		want := "Failed to launch: The program attribute is missing in debug configuration."
+		if got := expectErrorResponse(t, client, 0, "launch", "Failed to launch", 3000); got != nil && got.Body.Error.Format != want {
+			t.Errorf("got %q, want %q", got.Body.Error.Format, want)
+		}
+
+		// Skip detailed message checks for potentially different OS-specific errors.
+		client.LaunchRequest(fixture.Path+"_does_not_exist", false)
+		expectErrorResponse(t, client, 1, "launch", "Failed to launch", 3000)
+
+		client.LaunchRequest(fixture.Source, true) // Not an executable
+		expectErrorResponse(t, client, 2, "launch", "Failed to launch", 3000)
+
+		// We failed to launch the program. Make sure shutdown still works.
+		client.DisconnectRequest()
+		expectMessage(t, client, []byte(`{"seq":0,"type":"response","request_seq":3,"success":true,"command":"disconnect"}`))
+	})
+}