Repository: go-delve/delve
Pull request #2584 (2021-07-13 16:36:53)

service/dap: add len as metadata for map
This change adds an additional metadata variable for maps. There is currently no place that the size of a map is included. To make this information easier for users to access, we can add it as a named variable to be returned as a child of a map.

Map:
<img width="392" alt="Screen Shot 2021-07-13 at 12 32 40 PM" src="https://user-images.githubusercontent.com/6634754/125490758-318a2bf0-47f6-42d6-b62f-6a4e58359d67.png">


Paged Indexed:
<img width="661" alt="Screen Shot 2021-07-13 at 12 32 46 PM" src="https://user-images.githubusercontent.com/6634754/125490681-52a96595-3876-47f5-b003-473384a73f3f.png">

Empty map:
<img width="350" alt="Screen Shot 2021-07-13 at 12 36 14 PM" src="https://user-images.githubusercontent.com/6634754/125491317-510bffce-e670-4d1c-849b-3f795d0447e2.png">




Patch:
diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts
index adf35a88..f19ae009 100644
--- a/.teamcity/settings.kts
+++ b/.teamcity/settings.kts
@@ -35,7 +35,6 @@ To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View
 version = "2020.2"
 
 val targets = arrayOf(
-	"linux/amd64/1.14",
         "linux/amd64/1.15",
         "linux/amd64/1.16",
         "linux/amd64/1.17",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b4e6e73..2aa3dd05 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,49 @@
 All notable changes to this project will be documented in this file.
 This project adheres to Semantic Versioning.
 
+## [1.7.0] 2021-07-19
+
+### Added
+
+- Go 1.17 support (@aarzilli, @mknyszek)
+- Add new API and terminal command for setting watchpoints (@aarzilli)
+- Add filtering and grouping to goroutines command (@aarzilli)
+- Added support for hit count condition on breakpoints (@suzmue, @aarzilli)
+- DAP server: Handle SetVariable requests (@hyangah)
+- DAP server: Add clipboard support (@hyangah)
+
+### Fixed
+
+- DAP server: Several shutdown / disconnect fixes (@suzmue, @polinasok)
+- DAP server: Clean output executable name on Windows (@hyangah)
+- DAP server: Variables response must not have null variables array (@polinasok)
+- Fix runtimeTypeToDIE setup (necessary for Go 1.17) (@aarzilli)
+- Reenable CGO stacktrace test on arm64 (@derekparker)
+- Fix incorrect integer casts in freebsd C backend (@dwagin)
+- Ensure correct exit status reported on commands following process death (@derekparker)
+- Misc flakey test fixes / test refactoring (@polinasok)
+- Fix for frame parameter being ignored in ConvertEvalScope when no goroutine is found (@suzmue)
+- Ensure ContinueOnce returns StopExited if process exited, otherwise return StopUnknown (@polinasok)
+- Fix panic in RPC2.ListDynamicLibraries (@derekparker)
+- Fix typo in flag passed to check if debugserver supports unmask_signals (@staugust)
+
+### Changed
+
+- DAP server: Add sameuser security check (@hyangah)
+- DAP server: Changes to context-dependent load limits for string type (@hyangah, @polinasok)
+- DAP server: Add paging for arrays, slices and maps (@suzmue)
+- DAP server: Deemphasize internal runtime stack frames (@suzmue)
+- DAP server: Add throw reason to exception information upon panic (@suzmue)
+- DAP server: Set breakpoint hit ID (@suzmue)
+- DAP server: Add string value of byte/rune slice as child (@suzmue)
+- Documentation: Add viminspector to list of editor plugins (@aarzilli)
+- Support for ZMM registers in gdbserial backend (@aarzilli)
+- Remove support for stack barriers (@derekparker)
+- Improve support for DWARF5 (@derekparker)
+- Improve documentation (@derekparker, @aarzilli)
+- Print message and exit if Delve detects it is running under Rosetta on M1 macs (@aarzilli)
+- Drop official Go 1.14 support (@derekparker)
+
 ## [1.6.1] 2021-05-18
 
 ### Added
diff --git a/Documentation/usage/dlv.md b/Documentation/usage/dlv.md
index fdd3ca33..999ef679 100644
--- a/Documentation/usage/dlv.md
+++ b/Documentation/usage/dlv.md
@@ -41,7 +41,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 dap](dlv_dap.md)	 - [EXPERIMENTAL] Starts a headless 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
index 3a87a251..8fc171f3 100644
--- a/Documentation/usage/dlv_dap.md
+++ b/Documentation/usage/dlv_dap.md
@@ -1,13 +1,13 @@
 ## dlv dap
 
-[EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
+[EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
 
 ### Synopsis
 
 
-[EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
+[EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
 
-The server is headless and requires a DAP client like vscode to connect and request a binary
+The server is always headless and requires a DAP client like vscode to connect and request a binary
 to be launched or process to be attached to. The following modes are supported:
 - launch + exec (executes precompiled binary, like 'dlv exec')
 - launch + debug (builds and launches, like 'dlv debug')
diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go
index e063c728..2f8ec18d 100644
--- a/cmd/dlv/cmds/commands.go
+++ b/cmd/dlv/cmds/commands.go
@@ -174,10 +174,10 @@ option to let the process continue or kill it.
 	// '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).
+		Short: "[EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).",
+		Long: `[EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
 
-The server is headless and requires a DAP client like vscode to connect and request a binary
+The server is always headless and requires a DAP client like vscode to connect and request a binary
 to be launched or process to be attached to. The following modes are supported:
 - launch + exec (executes precompiled binary, like 'dlv exec')
 - launch + debug (builds and launches, like 'dlv debug')
@@ -188,6 +188,7 @@ While --continue is not supported, stopOnEntry launch/attach attribute can be us
 execution is resumed at the start of the debug session.`,
 		Run: dapCmd,
 	}
+	// TODO(polina): support --tty when dlv dap allows to launch a program from command-line
 	rootCommand.AddCommand(dapCommand)
 
 	// 'debug' subcommand.
@@ -409,7 +410,7 @@ func dapCmd(cmd *cobra.Command, args []string) {
 		}
 		defer logflags.Close()
 
-		if headless {
+		if cmd.Flag("headless").Changed {
 			fmt.Fprintf(os.Stderr, "Warning: dap mode is always headless\n")
 		}
 		if acceptMulti {
@@ -446,10 +447,9 @@ func dapCmd(cmd *cobra.Command, args []string) {
 			DisconnectChan: disconnectChan,
 			Debugger: debugger.Config{
 				Backend:              backend,
-				Foreground:           headless && tty == "",
+				Foreground:           true, // server always runs without terminal client
 				DebugInfoDirectories: conf.DebugInfoDirectories,
 				CheckGoVersion:       checkGoVersion,
-				TTY:                  tty,
 			},
 			CheckLocalConnUser: checkLocalConnUser,
 		})
diff --git a/pkg/goversion/compat.go b/pkg/goversion/compat.go
index 4e230294..b19528eb 100644
--- a/pkg/goversion/compat.go
+++ b/pkg/goversion/compat.go
@@ -6,7 +6,7 @@ import (
 
 var (
 	MinSupportedVersionOfGoMajor = 1
-	MinSupportedVersionOfGoMinor = 14
+	MinSupportedVersionOfGoMinor = 15
 	MaxSupportedVersionOfGoMajor = 1
 	MaxSupportedVersionOfGoMinor = 17
 	goTooOldErr                  = fmt.Errorf("Version of Go is too old for this version of Delve (minimum supported version %d.%d, suppress this error with --check-go-version=false)", MinSupportedVersionOfGoMajor, MinSupportedVersionOfGoMinor)
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 114218c2..e353a651 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -14,7 +14,7 @@ type Version struct {
 var (
 	// DelveVersion is the current version of Delve.
 	DelveVersion = Version{
-		Major: "1", Minor: "6", Patch: "1", Metadata: "",
+		Major: "1", Minor: "7", Patch: "0", Metadata: "",
 		Build: "$Id$",
 	}
 )
diff --git a/service/dap/server.go b/service/dap/server.go
index cec104ad..761d4dbd 100644
--- a/service/dap/server.go
+++ b/service/dap/server.go
@@ -972,6 +972,10 @@ func (s *Server) onDisconnectRequest(request *dap.DisconnectRequest) {
 	} else {
 		s.send(&dap.DisconnectResponse{Response: *newResponse(request.Request)})
 	}
+	// The debugging session has ended, so we send a terminated event.
+	s.send(&dap.TerminatedEvent{
+		Event: *newEvent("terminated"),
+	})
 }
 
 // stopDebugSession is called from Stop (main goroutine) and
@@ -1712,7 +1716,7 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 		}
 	}
 
-	var children []dap.Variable
+	children := []dap.Variable{} // must return empty array, not null, if no children
 	if request.Arguments.Filter == "named" || request.Arguments.Filter == "" {
 		named, err := s.metadataToDAPVariables(v)
 		if err != nil {
@@ -1765,7 +1769,7 @@ func (s *Server) childrenToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variab
 	// TODO(polina): consider convertVariableToString instead of convertVariable
 	// and avoid unnecessary creation of variable handles when this is called to
 	// compute evaluate names when this is called from onSetVariableRequest.
-	var children []dap.Variable
+	children := []dap.Variable{} // must return empty array, not null, if no children
 
 	switch v.Kind {
 	case reflect.Map:
@@ -1903,17 +1907,31 @@ func (s *Server) childrenToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variab
 
 func getNamedVariableCount(v *proc.Variable) int {
 	namedVars := 0
+	if v.Kind == reflect.Map && v.Len > 0 {
+		// len
+		namedVars += 1
+	}
 	if isListOfBytesOrRunes(v) {
 		// string value of array/slice of bytes and runes.
 		namedVars += 1
 	}
+
 	return namedVars
 }
 
 // metadataToDAPVariables returns the DAP presentation of the referenced variable's metadata.
 // These are included as named variables
 func (s *Server) metadataToDAPVariables(v *fullyQualifiedVariable) ([]dap.Variable, error) {
-	var children []dap.Variable
+	children := []dap.Variable{} // must return empty array, not null, if no children
+
+	if v.Kind == reflect.Map && v.Len > 0 {
+		children = append(children, dap.Variable{
+			Name:         "len()",
+			Value:        fmt.Sprintf("%d", v.Len),
+			Type:         "int",
+			EvaluateName: fmt.Sprintf("len(%s)", v.fullyQualifiedNameOrExpr),
+		})
+	}
 
 	if isListOfBytesOrRunes(v.Variable) {
 		// Return the string value of []byte or []rune.
diff --git a/service/rpc2/server.go b/service/rpc2/server.go
index 056900ed..b51f4045 100644
--- a/service/rpc2/server.go
+++ b/service/rpc2/server.go
@@ -838,7 +838,7 @@ func (s *RPCServer) ListDynamicLibraries(in ListDynamicLibrariesIn, out *ListDyn
 	imgs := s.debugger.ListDynamicLibraries()
 	out.List = make([]api.Image, 0, len(imgs))
 	for i := range imgs {
-		out.List[i] = api.ConvertImage(imgs[i])
+		out.List = append(out.List, api.ConvertImage(imgs[i]))
 	}
 	return nil
 }


Test patch:
diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go
index 2c5b23a7..479ac40e 100644
--- a/cmd/dlv/dlv_test.go
+++ b/cmd/dlv/dlv_test.go
@@ -637,6 +637,7 @@ func TestDap(t *testing.T) {
 	client := daptest.NewClient(listenAddr)
 	client.DisconnectRequest()
 	client.ExpectDisconnectResponse(t)
+	client.ExpectTerminatedEvent(t)
 	if _, err := client.ReadMessage(); err != io.EOF {
 		t.Errorf("got %q, want \"EOF\"\n", err)
 	}
diff --git a/service/dap/server_test.go b/service/dap/server_test.go
index 23084425..08872dcb 100644
--- a/service/dap/server_test.go
+++ b/service/dap/server_test.go
@@ -246,6 +246,7 @@ func TestLaunchStopOnEntry(t *testing.T) {
 		if dResp.Seq != 0 || dResp.RequestSeq != 13 {
 			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=13", dResp)
 		}
+		client.ExpectTerminatedEvent(t)
 	})
 }
 
@@ -377,6 +378,7 @@ func TestAttachStopOnEntry(t *testing.T) {
 		client.CheckOutputEvent(t, msg)
 		msg = expectMessageFilterStopped(t, client)
 		client.CheckDisconnectResponse(t, msg)
+		client.ExpectTerminatedEvent(t)
 
 		// If this call to KeepAlive isn't here there's a chance that stdout will
 		// be garbage collected (since it is no longer alive long before this
@@ -452,6 +454,7 @@ func TestContinueOnEntry(t *testing.T) {
 		if dResp.Seq != 0 || dResp.RequestSeq != 8 {
 			t.Errorf("\ngot %#v\nwant Seq=0, RequestSeq=8", dResp)
 		}
+		client.ExpectTerminatedEvent(t)
 	})
 }
 
@@ -591,6 +594,7 @@ func TestPreSetBreakpoint(t *testing.T) {
 		client.ExpectOutputEventProcessExited(t, 0)
 		client.ExpectOutputEventDetaching(t)
 		client.ExpectDisconnectResponse(t)
+		client.ExpectTerminatedEvent(t)
 	})
 }
 
@@ -654,6 +658,9 @@ func checkScope(t *testing.T, got *dap.ScopesResponse, i int, name string, varRe
 //      numChildren - number of variables/fields/elements of this variable
 func checkChildren(t *testing.T, got *dap.VariablesResponse, parentName string, numChildren int) {
 	t.Helper()
+	if got.Body.Variables == nil {
+		t.Errorf("\ngot  %s children=%#v want []", parentName, got.Body.Variables)
+	}
 	if len(got.Body.Variables) != numChildren {
 		t.Errorf("\ngot  len(%s)=%d (children=%#v)\nwant len=%d", parentName, len(got.Body.Variables), got.Body.Variables, numChildren)
 	}
@@ -1281,8 +1288,9 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m2 := client.ExpectVariablesResponse(t)
-						checkChildren(t, m2, "m2", 1) // each key-value represented by a single child
-						ref = checkVarExact(t, m2, 0, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", "int: *main.astruct", hasChildren)
+						checkChildren(t, m2, "m2", 2) // each key-value represented by a single child
+						checkVarExact(t, m2, 0, "len()", "len(m2)", "1", "int", noChildren)
+						ref = checkVarExact(t, m2, 1, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", "int: *main.astruct", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m2kv1 := client.ExpectVariablesResponse(t)
@@ -1304,8 +1312,9 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m3 := client.ExpectVariablesResponse(t)
-						checkChildren(t, m3, "m3", 2) // each key-value represented by a single child
-						ref = checkVarRegex(t, m3, 0, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", "int", hasChildren)
+						checkChildren(t, m3, "m3", 3) // each key-value represented by a single child
+						checkVarExact(t, m3, 0, "len()", "len(m3)", "2", "int", noChildren)
+						ref = checkVarRegex(t, m3, 1, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", "int", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m3kv0 := client.ExpectVariablesResponse(t)
@@ -1313,7 +1322,7 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 							checkVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", "int", noChildren)
 							validateEvaluateName(t, client, m3kv0, 0)
 						}
-						ref = checkVarRegex(t, m3, 1, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", "", hasChildren)
+						ref = checkVarRegex(t, m3, 2, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", "", hasChildren)
 						if ref > 0 { // inspect another key from another key-value child
 							client.VariablesRequest(ref)
 							m3kv1 := client.ExpectVariablesResponse(t)
@@ -1327,10 +1336,11 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m4 := client.ExpectVariablesResponse(t)
-						checkChildren(t, m4, "m4", 4) // each key and value represented by a child, so double the key-value count
-						checkVarRegex(t, m4, 0, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `main\.astruct`, hasChildren)
-						checkVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
-						ref = checkVarRegex(t, m4, 2, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, `main\.astruct`, hasChildren)
+						checkChildren(t, m4, "m4", 5) // each key and value represented by a child, so double the key-value count
+						checkVarExact(t, m4, 0, "len()", "len(m4)", "2", "int", noChildren)
+						checkVarRegex(t, m4, 1, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `main\.astruct`, hasChildren)
+						checkVarRegex(t, m4, 2, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
+						ref = checkVarRegex(t, m4, 3, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, `main\.astruct`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m4Key1 := client.ExpectVariablesResponse(t)
@@ -1340,7 +1350,7 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 							validateEvaluateName(t, client, m4Key1, 0)
 							validateEvaluateName(t, client, m4Key1, 1)
 						}
-						ref = checkVarRegex(t, m4, 3, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, "main.astruct", hasChildren)
+						ref = checkVarRegex(t, m4, 4, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, "main.astruct", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m4Val1 := client.ExpectVariablesResponse(t)
@@ -1548,11 +1558,11 @@ func TestVariablesLoading(t *testing.T) {
 
 					// Map not fully loaded based on LoadConfig.MaxArrayValues
 					// Expect to be able to load map by paging.
-					ref = checkVarRegexIndexed(t, locals, -1, "m1", "m1", `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren, 66, 0)
+					ref = checkVarRegexIndexed(t, locals, -1, "m1", "m1", `map\[string\]main\.astruct \[.+\.\.\.`, `map\[string\]main\.astruct`, hasChildren, 66, 1)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m1 := client.ExpectVariablesResponse(t)
-						checkChildren(t, m1, "m1", 64)
+						checkChildren(t, m1, "m1", 65)
 
 						client.IndexedVariablesRequest(ref, 0, 66)
 						m1 = client.ExpectVariablesResponse(t)
@@ -1580,6 +1590,10 @@ func TestVariablesLoading(t *testing.T) {
 								}
 							}
 						}
+						client.NamedVariablesRequest(ref)
+						named := client.ExpectVariablesResponse(t)
+						checkChildren(t, named, "m1", 1)
+						checkVarExact(t, named, 0, "len()", "len(m1)", "66", "int", noChildren)
 					}
 
 					// Struct partially missing based on LoadConfig.MaxStructFields
@@ -1658,7 +1672,7 @@ func TestVariablesLoading(t *testing.T) {
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								tmV0 := client.ExpectVariablesResponse(t)
-								checkChildren(t, tmV0, "tm.v[0]", 64)
+								checkChildren(t, tmV0, "tm.v[0]", 65)
 							}
 						}
 					}
@@ -1688,7 +1702,7 @@ func TestVariablesLoading(t *testing.T) {
 								if ref > 0 {
 									client.VariablesRequest(ref)
 									tmV0 := client.ExpectVariablesResponse(t)
-									checkChildren(t, tmV0, "tm.v[0]", 64)
+									checkChildren(t, tmV0, "tm.v[0]", 65)
 								}
 							}
 						}
@@ -3045,20 +3059,20 @@ func TestVariableValueTruncation(t *testing.T) {
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						// Key format: <truncated>... @<address>
-						checkVarRegex(t, client.ExpectVariablesResponse(t), 0, `main\.C {s: "very long string 0123456789.+\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
+						checkVarRegex(t, client.ExpectVariablesResponse(t), 1, `main\.C {s: "very long string 0123456789.+\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
 					}
 					// key - scalar, value - scalar (inlined key:value display) => key not truncated
 					ref = checkVarExact(t, locals, -1, "m6", "m6", "map[string]int ["+longstr+": 123, ]", "map[string]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
-						checkVarExact(t, client.ExpectVariablesResponse(t), 0, longstr, `m6[`+longstr+`]`, "123", "string: int", noChildren)
+						checkVarExact(t, client.ExpectVariablesResponse(t), 1, longstr, `m6[`+longstr+`]`, "123", "string: int", noChildren)
 					}
 					// key - compound, value - compound (array-like display) => key not truncated
 					ref = checkVarExact(t, locals, -1, "m7", "m7", "map[main.C]main.C [{s: "+longstr+"}: {s: \"hello\"}, ]", "map[main.C]main.C", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m7 := client.ExpectVariablesResponse(t)
-						checkVarRegex(t, m7, 0, "[key 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstr+`}`, `main\.C`, hasChildren)
+						checkVarRegex(t, m7, 1, "[key 0]", `\(\*\(\*\"main\.C\"\)\(0x[0-9a-f]+\)\)`, `main\.C {s: `+longstr+`}`, `main\.C`, hasChildren)
 					}
 				},
 				disconnect: true,
@@ -3854,6 +3868,7 @@ func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cm
 				client.ExpectOutputEventDetachingKill(t)
 			}
 			client.ExpectDisconnectResponse(t)
+			client.ExpectTerminatedEvent(t)
 			return
 		}
 		client.ContinueRequest(1)
@@ -3872,6 +3887,7 @@ func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cm
 		client.ExpectOutputEventDetachingKill(t)
 	}
 	client.ExpectDisconnectResponse(t)
+	client.ExpectTerminatedEvent(t)
 }
 
 // runDebugSession is a helper for executing the standard init and shutdown
@@ -3996,6 +4012,7 @@ func runNoDebugDebugSession(t *testing.T, client *daptest.Client, cmdRequest fun
 	client.ExpectTerminatedEvent(t)
 	client.DisconnectRequestWithKillOption(true)
 	client.ExpectDisconnectResponse(t)
+	client.ExpectTerminatedEvent(t)
 }
 
 func TestLaunchTestRequest(t *testing.T) {
@@ -4390,7 +4407,7 @@ func TestSetVariable(t *testing.T) {
 					tester.evaluate(`m1["Malone"]`, "main.astruct {A: 2, B: 3}", hasChildren)
 					m1Ref := checkVarRegex(t, locals, -1, "m1", "m1", `.*map\[string\]main\.astruct.*`, `map\[string\]main\.astruct`, hasChildren)
 					m1 := tester.variables(m1Ref)
-					elem1 := m1.Body.Variables[0]
+					elem1 := m1.Body.Variables[1]
 					tester.expectSetVariable(elem1.VariablesReference, "A", "-9999")
 					tester.expectSetVariable(elem1.VariablesReference, "B", "10000")
 					tester.evaluate(elem1.EvaluateName, "main.astruct {A: -9999, B: 10000}", hasChildren)