Repository: go-delve/delve
Pull request #2300 (2021-01-13 17:26:51)

proc: refactor common code in WriteBreakpoint
Moves common backend code in WriteBreakpoint to
proc.(*Target).SetBreakpoint.


aarzilli: Note: this is setup for #2301

Patch:
diff --git a/.gitignore b/.gitignore
index 82378981..b117424d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,6 @@ cmd/dlv/dlv
 .vagrant
 **/*.swp
 localtests
+.idea
+*.iml
+.teamcity/target
diff --git a/.teamcity/pom.xml b/.teamcity/pom.xml
new file mode 100644
index 00000000..1292800a
--- /dev/null
+++ b/.teamcity/pom.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <name>Delve Config DSL Script</name>
+  <groupId>Delve</groupId>
+  <artifactId>Delve_dsl</artifactId>
+  <version>1.0-SNAPSHOT</version>
+
+  <parent>
+    <groupId>org.jetbrains.teamcity</groupId>
+    <artifactId>configs-dsl-kotlin-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <repositories>
+    <repository>
+      <id>jetbrains-all</id>
+      <url>https://download.jetbrains.com/teamcity-repository</url>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+    </repository>
+    <repository>
+      <id>teamcity-server</id>
+      <url>https://delve.beta.teamcity.com/app/dsl-plugins-repository</url>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+
+  <pluginRepositories>
+    <pluginRepository>
+      <id>JetBrains</id>
+      <url>https://download.jetbrains.com/teamcity-repository</url>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <build>
+    <sourceDirectory>${basedir}</sourceDirectory>
+    <plugins>
+      <plugin>
+        <artifactId>kotlin-maven-plugin</artifactId>
+        <groupId>org.jetbrains.kotlin</groupId>
+        <version>${kotlin.version}</version>
+
+        <configuration/>
+        <executions>
+          <execution>
+            <id>compile</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>test-compile</id>
+            <phase>process-test-sources</phase>
+            <goals>
+              <goal>test-compile</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.jetbrains.teamcity</groupId>
+        <artifactId>teamcity-configs-maven-plugin</artifactId>
+        <version>${teamcity.dsl.version}</version>
+        <configuration>
+          <format>kotlin</format>
+          <dstDir>target/generated-configs</dstDir>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.jetbrains.teamcity</groupId>
+      <artifactId>configs-dsl-kotlin</artifactId>
+      <version>${teamcity.dsl.version}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jetbrains.teamcity</groupId>
+      <artifactId>configs-dsl-kotlin-plugins</artifactId>
+      <version>1.0-SNAPSHOT</version>
+      <type>pom</type>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jetbrains.kotlin</groupId>
+      <artifactId>kotlin-stdlib-jdk8</artifactId>
+      <version>${kotlin.version}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jetbrains.kotlin</groupId>
+      <artifactId>kotlin-script-runtime</artifactId>
+      <version>${kotlin.version}</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file
diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts
new file mode 100644
index 00000000..ec8b3cb5
--- /dev/null
+++ b/.teamcity/settings.kts
@@ -0,0 +1,214 @@
+import jetbrains.buildServer.configs.kotlin.v2019_2.*
+import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.PullRequests
+import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.commitStatusPublisher
+import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang
+import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.pullRequests
+import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.dockerCommand
+import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.powerShell
+import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric
+import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange
+import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
+
+/*
+The settings script is an entry point for defining a TeamCity
+project hierarchy. The script should contain a single call to the
+project() function with a Project instance or an init function as
+an argument.
+
+VcsRoots, BuildTypes, Templates, and subprojects can be
+registered inside the project using the vcsRoot(), buildType(),
+template(), and subProject() methods respectively.
+
+To debug settings scripts in command-line, run the
+
+    mvnDebug org.jetbrains.teamcity:teamcity-configs-maven-plugin:generate
+
+command and attach your debugger to the port 8000.
+
+To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View
+-> Tool Windows -> Maven Projects), find the generate task node
+(Plugins -> teamcity-configs -> teamcity-configs:generate), the
+'Debug' option is available in the context menu for the task.
+*/
+
+version = "2020.2"
+
+val targets = arrayOf(
+	"linux/amd64/1.13",
+	"linux/amd64/1.14",
+        "linux/amd64/1.15",
+        "linux/amd64/1.16",
+        "linux/amd64/tip",
+
+        "linux/386/1.15",
+
+        "windows/amd64/1.15",
+        "windows/amd64/1.16",
+        "windows/amd64/tip"
+)
+
+project {
+    val tests = targets.map { target ->
+        val (os, arch, version) = target.split("/")
+        TestBuild(os, arch, version, AbsoluteId("Delve_${os}_${arch}_${version.replace('.', '_')}"))
+    }
+    tests.map { test ->
+        test.os
+    }.distinct().forEach { os ->
+        subProject(OSProject(os, tests.filter { test ->
+            test.os == os
+        }))
+    }
+    buildType(AggregatorBuild(tests))
+}
+
+class AggregatorBuild(tests: Collection<BuildType>) : BuildType({
+    name = "Aggregator"
+    type = Type.COMPOSITE
+
+    vcs {
+        root(DslContext.settingsRoot)
+    }
+
+    triggers {
+        vcs {
+        }
+    }
+
+    dependencies {
+        tests.forEach { test ->
+            snapshot(test) {
+            }
+        }
+    }
+
+    features {
+        pullRequests {
+            vcsRootExtId = "${DslContext.settingsRoot.id}"
+            provider = github {
+                authType = token {
+                    token = "credentialsJSON:5dc93081-e0b2-41e2-b8f0-dea3c96e6426"
+                }
+                filterAuthorRole = PullRequests.GitHubRoleFilter.EVERYBODY
+            }
+        }
+        commitStatusPublisher {
+            vcsRootExtId = "${DslContext.settingsRoot.id}"
+            publisher = github {
+                githubUrl = "https://api.github.com"
+                authType = personalToken {
+                    token = "credentialsJSON:48af6e38-536d-4acb-ae2d-2fba57b6f3db"
+                }
+            }
+            param("github_oauth_user", "")
+        }
+    }
+})
+
+class OSProject(os: String, tests: List<TestBuild>) : Project({
+    id = AbsoluteId("Delve_$os")
+    name = os.capitalize()
+
+    tests.map { test ->
+        test.arch
+    }.distinct().forEach { arch ->
+        subProject(ArchProject(os, arch, tests.filter { test ->
+            test.arch == arch
+        }))
+    }
+})
+
+class ArchProject(os: String, arch: String, tests: List<TestBuild>) : Project({
+    id = AbsoluteId("Delve_${os}_${arch}")
+    name = arch
+
+    tests.forEach { test ->
+        buildType(test)
+    }
+})
+
+class TestBuild(val os: String, val arch: String, version: String, buildId: AbsoluteId) : BuildType({
+    id = buildId
+    name = version
+
+    vcs {
+        root(DslContext.settingsRoot)
+    }
+
+    failureConditions {
+        executionTimeoutMin = 30
+
+        if (version != "tip") {
+            failOnMetricChange {
+                 metric = BuildFailureOnMetric.MetricType.TEST_COUNT
+                 units = BuildFailureOnMetric.MetricUnit.DEFAULT_UNIT
+                 comparison = BuildFailureOnMetric.MetricComparison.LESS
+                 compareTo = value()
+            }
+        }
+    }
+
+    steps {
+        when (os) {
+            "linux" -> {
+                val dockerArch = if (arch == "386") "i$arch" else arch
+                dockerCommand {
+                    name = "Pull Ubuntu"
+                    commandType = other {
+                        subCommand = "pull"
+                        commandArgs = "$dockerArch/ubuntu:20.04"
+                    }
+                }
+                dockerCommand {
+                    name = "Test"
+                    commandType = other {
+                        subCommand = "run"
+                        commandArgs = """
+                        -v %teamcity.build.checkoutDir%:/delve
+                        --env TEAMCITY_VERSION=${'$'}TEAMCITY_VERSION
+                        --env CI=true
+                        --privileged
+                        $dockerArch/ubuntu:20.04
+                        /delve/_scripts/test_linux.sh ${"go$version"} $arch
+                    """.trimIndent()
+                    }
+                }
+            }
+            "windows" -> {
+                powerShell {
+                    name = "Test"
+                    scriptMode = file {
+                        path = "_scripts/test_windows.ps1"
+                    }
+                    param("jetbrains_powershell_scriptArguments", "-version ${"go$version"} -arch $arch")
+                }
+            }
+        }
+    }
+
+    requirements {
+        when (os) {
+            "linux" -> {
+                matches("teamcity.agent.jvm.os.family", "Linux")
+            }
+            "windows" -> {
+                matches("teamcity.agent.jvm.os.family", "Windows")
+            }
+        }
+    }
+
+    features {
+        pullRequests {
+            vcsRootExtId = "${DslContext.settingsRoot.id}"
+            provider = github {
+                authType = token {
+                    token = "credentialsJSON:5dc93081-e0b2-41e2-b8f0-dea3c96e6426"
+                }
+                filterAuthorRole = PullRequests.GitHubRoleFilter.EVERYBODY
+            }
+        }
+        golang {
+            testFormat = "json"
+        }
+    }
+})
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index f67ecf3d..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-language: go
-sudo: required
-go_import_path: github.com/go-delve/delve
-
-os:
-  - linux
-
-arch:
-  - amd64
-  - arm64
-
-go:
-  - 1.15.3 # hold back version of Go, see issue #42484
-  - tip
-
-matrix:
-  allow_failures:
-    - go: tip
-  exclude:
-    - arch: arm64
-      go: tip
-
-before_install:
-  - export GOFLAGS=-mod=vendor
-  - if [ $TRAVIS_OS_NAME = "linux" ]; then sudo apt-get -qq update; sudo apt-get install -y dwz; echo "dwz version $(dwz --version)"; fi
-
-
-# 386 linux
-jobs:
-  include:
-    -  os: linux
-       services: docker
-       env: go_32_version=1.15.2 # Linux/i386 tests will fail on go1.15 prior to 1.15.2 (see issue #2134)
-
-script: >-
-    if [ $TRAVIS_OS_NAME = "linux" ] && [ $go_32_version ]; then
-      docker pull i386/centos:7;
-      docker run \
-      -v $(pwd):/delve \
-      --env TRAVIS=true \
-      --env CI=true \
-      --privileged i386/centos:7 \
-      /bin/bash -c "set -x && \
-           cd delve && \
-           yum -y update && yum -y upgrade && \
-           yum -y install wget make git gcc && \
-           wget -q https://dl.google.com/go/go${go_32_version}.linux-386.tar.gz && \
-           tar -C /usr/local -xzf go${go_32_version}.linux-386.tar.gz && \
-           export PATH=$PATH:/usr/local/go/bin && \
-           go version && \
-           uname -a && \
-           make test";
-    else
-      make test;
-    fi
-  
-cache:
-  directories:
-    - $HOME/AppData/Local/Temp/chocolatey
diff --git a/README.md b/README.md
index 8d2595f9..73fb876b 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,7 @@
 
 [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/go-delve/delve/master/LICENSE)
 [![GoDoc](https://godoc.org/github.com/go-delve/delve?status.svg)](https://godoc.org/github.com/go-delve/delve)
-[![Build Status](https://travis-ci.org/go-delve/delve.svg?branch=master)](https://travis-ci.org/go-delve/delve)
-[![Build status](https://ci.appveyor.com/api/projects/status/0v8r99smxost466s/branch/master?svg=true)](https://ci.appveyor.com/project/derekparker/delve-facy3/branch/master)
+[![Build Status](https://delve.beta.teamcity.com/app/rest/builds/buildType:(id:Delve_AggregatorBuild)/statusIcon.svg)](https://delve.beta.teamcity.com/viewType.html?buildTypeId=Delve_AggregatorBuild&guest=1)
 
 The GitHub issue tracker is for **bugs** only. Please use the [developer mailing list](https://groups.google.com/forum/#!forum/delve-dev) for any feature proposals and discussions.
 
diff --git a/_scripts/gen-travis.go b/_scripts/gen-travis.go
index 2f4cf25b..a6028c92 100644
--- a/_scripts/gen-travis.go
+++ b/_scripts/gen-travis.go
@@ -55,87 +55,12 @@ func main() {
 		}
 	}
 
-	travisfh, err := os.Create(".travis.yml")
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "could not create .travis.yml: %v")
-		os.Exit(1)
-	}
-
-	out := bufio.NewWriter(travisfh)
-	err = template.Must(template.New("travis.yml").Parse(`language: go
-sudo: required
-go_import_path: github.com/go-delve/delve
-
-os:
-  - linux
-
-arch:
-  - amd64
-  - arm64
-
-go:
-  - {{index .GoVersions 0}}
-  - tip
-
-matrix:
-  allow_failures:
-    - go: tip
-  exclude:
-    - arch: arm64
-      go: tip
-
-before_install:
-  - export GOFLAGS=-mod=vendor
-  - if [ $TRAVIS_OS_NAME = "linux" ]; then sudo apt-get -qq update; sudo apt-get install -y dwz; echo "dwz version $(dwz --version)"; fi
-
-
-# 386 linux
-jobs:
-  include:
-    -  os: linux
-       services: docker
-       env: go_32_version={{index .GoVersions 0}}.2 # Linux/i386 tests will fail on go1.15 prior to 1.15.2 (see issue #2134)
-
-script: >-
-    if [ $TRAVIS_OS_NAME = "linux" ] && [ $go_32_version ]; then
-      docker pull i386/centos:7;
-      docker run \
-      -v $(pwd):/delve \
-      --env TRAVIS=true \
-      --env CI=true \
-      --privileged i386/centos:7 \
-      /bin/bash -c "set -x && \
-           cd delve && \
-           yum -y update && yum -y upgrade && \
-           yum -y install wget make git gcc && \
-           wget -q https://dl.google.com/go/go${go_32_version}.linux-386.tar.gz && \
-           tar -C /usr/local -xzf go${go_32_version}.linux-386.tar.gz && \
-           export PATH=$PATH:/usr/local/go/bin && \
-           go version && \
-           uname -a && \
-           make test";
-    else
-      make test;
-    fi
-  
-cache:
-  directories:
-    - $HOME/AppData/Local/Temp/chocolatey
-`)).Execute(out, args)
-
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "Error executing template: %v", err)
-		os.Exit(1)
-	}
-	_ = out.Flush()
-	_ = travisfh.Close()
-
 	githubfh, err := os.Create(".github/workflows/test.yml")
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Could not create .github/test.yml: %v", err)
 		os.Exit(1)
 	}
-	out = bufio.NewWriter(githubfh)
+	out := bufio.NewWriter(githubfh)
 	err = template.Must(template.New(".github/workflows/test.yml").Parse(`name: Delve CI
 
 on: [push, pull_request]
diff --git a/_scripts/make.go b/_scripts/make.go
index 1580bb5c..40e35072 100644
--- a/_scripts/make.go
+++ b/_scripts/make.go
@@ -276,6 +276,9 @@ func testFlags() []string {
 		// Make test timeout shorter than Travis' own timeout so that Go can report which test hangs.
 		testFlags = append(testFlags, "-timeout", "9m")
 	}
+	if len(os.Getenv("TEAMCITY_VERSION")) > 0 {
+		testFlags = append(testFlags, "-json")
+	}
 	if runtime.GOOS == "darwin" {
 		testFlags = append(testFlags, "-exec="+wd+"/_scripts/testsign")
 	}
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 74035298..00000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-version: '{build}'
-os: Windows Server 2012 R2
-clone_folder: c:\gopath\src\github.com\go-delve\delve
-environment:
-  GOPATH: C:\gopath
-install:
-   ps: |
-      # Install MinGW.
-      if (-Not (Test-Path "C:\mingw64")) {
-              $file = "x86_64-4.9.2-release-win32-seh-rt_v4-rev3.7z"
-              $url  = "https://bintray.com/artifact/download/drewwells/generic/"
-              $url += $file
-              Invoke-WebRequest -UserAgent wget -Uri $url -OutFile $file
-              &7z x -oC:\ $file > $null
-      }
-      # Install Procdump
-      if (-Not (Test-Path "C:\procdump")) {
-              mkdir c:\procdump
-              Invoke-WebRequest -UserAgent wget -Uri https://download.sysinternals.com/files/Procdump.zip -OutFile C:\procdump\procdump.zip
-              &7z x -oC:\procdump\ C:\procdump\procdump.zip > $null
-      }
-   set PATH=c:\procdump;c:\mingw64\bin;%GOPATH%\bin;%PATH%
-   echo %PATH%
-   echo %GOPATH%
-   go version
-   go env
-cache:
-   C:\mingw64
-   C:\procdump
-build_script:
- mingw32-make install
-test_script:
- mingw32-make test
diff --git a/pkg/dwarf/dwarfbuilder/info.go b/pkg/dwarf/dwarfbuilder/info.go
index 7d264b01..31eb15b0 100644
--- a/pkg/dwarf/dwarfbuilder/info.go
+++ b/pkg/dwarf/dwarfbuilder/info.go
@@ -123,10 +123,11 @@ func (b *Builder) TagClose() {
 }
 
 // Attr adds an attribute to the current DIE.
-func (b *Builder) Attr(attr dwarf.Attr, val interface{}) {
+func (b *Builder) Attr(attr dwarf.Attr, val interface{}) dwarf.Offset {
 	if len(b.tagStack) < 0 {
 		panic("Attr with no open tags")
 	}
+	off := dwarf.Offset(b.info.Len())
 	tag := b.tagStack[len(b.tagStack)-1]
 	if tag.children {
 		panic("Can't add attributes after adding children")
@@ -179,6 +180,16 @@ func (b *Builder) Attr(attr dwarf.Attr, val interface{}) {
 	default:
 		panic("unknown value type")
 	}
+
+	return off
+}
+
+// PatchOffset writes the offset 'patch' at offset patchedOffset.
+func (b *Builder) PatchOffset(patchedOffset, patch dwarf.Offset) {
+	infoBytes := b.info.Bytes()
+	buf := new(bytes.Buffer)
+	binary.Write(buf, binary.LittleEndian, patch)
+	copy(infoBytes[patchedOffset:], buf.Bytes())
 }
 
 func sameTagDescr(a, b tagDescr) bool {
diff --git a/pkg/proc/arm64_arch.go b/pkg/proc/arm64_arch.go
index e12f2a69..49b9395a 100644
--- a/pkg/proc/arm64_arch.go
+++ b/pkg/proc/arm64_arch.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"encoding/binary"
 	"fmt"
-	"io"
 	"strings"
 
 	"github.com/go-delve/delve/pkg/dwarf/frame"
@@ -390,33 +389,37 @@ func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floa
 		var out bytes.Buffer
 		var vi [16]uint8
 		for i := range vi {
-			binary.Read(buf, binary.LittleEndian, &vi[i])
+			_ = 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, io.SeekStart)
-		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, io.SeekStart)
-		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])
-
+		//D
+		fmt.Fprintf(&out, " {\n\tD = {u = {0x%02x%02x%02x%02x%02x%02x%02x%02x,", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
+		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x%02x%02x%02x%02x},", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
+		fmt.Fprintf(&out, " s = {0x%02x%02x%02x%02x%02x%02x%02x%02x,", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
+		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x%02x%02x%02x%02x}},", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
+
+		//S
+		fmt.Fprintf(&out, " \n\tS = {u = {0x%02x%02x%02x%02x,0x%02x%02x%02x%02x,", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4])
+		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x,0x%02x%02x%02x%02x},", vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
+		fmt.Fprintf(&out, " s = {0x%02x%02x%02x%02x,0x%02x%02x%02x%02x,", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4])
+		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x,0x%02x%02x%02x%02x}},", vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
+
+		//H
+		fmt.Fprintf(&out, " \n\tH = {u = {0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6])
+		fmt.Fprintf(&out, " 0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x},", vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
+		fmt.Fprintf(&out, " s = {0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6])
+		fmt.Fprintf(&out, " 0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x}},", vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
+
+		//B
+		fmt.Fprintf(&out, " \n\tB = {u = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7])
+		fmt.Fprintf(&out, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x},", vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
+		fmt.Fprintf(&out, " s = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7])
+		fmt.Fprintf(&out, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}}", vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
+
+		//Q
+		fmt.Fprintf(&out, " \n\tQ = {u = {0x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
+		fmt.Fprintf(&out, "%02x%02x%02x%02x%02x%02x%02x%02x},", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
+		fmt.Fprintf(&out, " s = {0x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
+		fmt.Fprintf(&out, "%02x%02x%02x%02x%02x%02x%02x%02x}}\n\t}", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
 		return name, true, out.String()
 	} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) < 16) {
 		return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)
diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go
index a4f2bb14..196280f4 100644
--- a/pkg/proc/bininfo.go
+++ b/pkg/proc/bininfo.go
@@ -1787,18 +1787,15 @@ func (bi *BinaryInfo) addAbstractSubprogram(entry *dwarf.Entry, ctxt *loadDebugI
 		return
 	}
 
-	fn := Function{
-		Name:   name,
-		offset: entry.Offset,
-		cu:     cu,
-	}
-
 	if entry.Children {
 		bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
 	}
 
-	bi.Functions = append(bi.Functions, fn)
-	ctxt.abstractOriginTable[entry.Offset] = len(bi.Functions) - 1
+	originIdx := ctxt.lookupAbstractOrigin(bi, entry.Offset)
+	fn := &bi.Functions[originIdx]
+	fn.Name = name
+	fn.offset = entry.Offset
+	fn.cu = cu
 }
 
 // addConcreteInlinedSubprogram adds the concrete entry of a subprogram that was also inlined.
@@ -1812,15 +1809,7 @@ func (bi *BinaryInfo) addConcreteInlinedSubprogram(entry *dwarf.Entry, originOff
 		return
 	}
 
-	originIdx, ok := ctxt.abstractOriginTable[originOffset]
-	if !ok {
-		bi.logger.Warnf("reading debug_info: could not find abstract origin of concrete inlined subprogram at %#x (origin offset %#x)", entry.Offset, originOffset)
-		if entry.Children {
-			reader.SkipChildren()
-		}
-		return
-	}
-
+	originIdx := ctxt.lookupAbstractOrigin(bi, originOffset)
 	fn := &bi.Functions[originIdx]
 	fn.offset = entry.Offset
 	fn.Entry = lowpc
@@ -1905,12 +1894,7 @@ func (bi *BinaryInfo) loadDebugInfoMapsInlinedCalls(ctxt *loadDebugInfoMapsConte
 				continue
 			}
 
-			originIdx, ok := ctxt.abstractOriginTable[originOffset]
-			if !ok {
-				bi.logger.Warnf("reading debug_info: could not find abstract origin (%#x) of inlined call at %#x", originOffset, entry.Offset)
-				reader.SkipChildren()
-				continue
-			}
+			originIdx := ctxt.lookupAbstractOrigin(bi, originOffset)
 			fn := &bi.Functions[originIdx]
 
 			lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
diff --git a/pkg/proc/breakpoints.go b/pkg/proc/breakpoints.go
index 443f54b9..2b4d4cb5 100644
--- a/pkg/proc/breakpoints.go
+++ b/pkg/proc/breakpoints.go
@@ -263,10 +263,7 @@ func (t *Target) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr)
 		return bp, nil
 	}
 
-	f, l, fn, originalData, err := t.proc.WriteBreakpoint(addr)
-	if err != nil {
-		return nil, err
-	}
+	f, l, fn := t.BinInfo().PCToLine(uint64(addr))
 
 	fnName := ""
 	if fn != nil {
@@ -279,10 +276,14 @@ func (t *Target) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr)
 		Line:         l,
 		Addr:         addr,
 		Kind:         kind,
-		OriginalData: originalData,
 		HitCount:     map[int]uint64{},
 	}
 
+	err := t.proc.WriteBreakpoint(newBreakpoint)
+	if err != nil {
+		return nil, err
+	}
+
 	if kind != UserBreakpoint {
 		bpmap.internalBreakpointIDCounter++
 		newBreakpoint.LogicalID = bpmap.internalBreakpointIDCounter
diff --git a/pkg/proc/core/core.go b/pkg/proc/core/core.go
index 93bb277d..0406d045 100644
--- a/pkg/proc/core/core.go
+++ b/pkg/proc/core/core.go
@@ -231,8 +231,8 @@ func (p *process) EntryPoint() (uint64, error) {
 
 // WriteBreakpoint is a noop function since you
 // cannot write breakpoints into core files.
-func (p *process) WriteBreakpoint(addr uint64) (file string, line int, fn *proc.Function, originalData []byte, err error) {
-	return "", 0, nil, nil, errors.New("cannot write a breakpoint to a core file")
+func (p *process) WriteBreakpoint(*proc.Breakpoint) error {
+	return errors.New("cannot write a breakpoint to a core file")
 }
 
 // Recorded returns whether this is a live or recorded process. Always returns true for core files.
diff --git a/pkg/proc/eval.go b/pkg/proc/eval.go
index cec7641e..f6722fa2 100644
--- a/pkg/proc/eval.go
+++ b/pkg/proc/eval.go
@@ -36,8 +36,6 @@ type EvalScope struct {
 
 	frameOffset int64
 
-	aordr *dwarf.Reader // extra reader to load DW_AT_abstract_origin entries, do not initialize
-
 	// When the following pointer is not nil this EvalScope was created
 	// by CallFunction and the expression evaluation is executing on a
 	// different goroutine from the debugger's main goroutine.
@@ -558,14 +556,6 @@ func (scope *EvalScope) image() *Image {
 	return scope.BinInfo.funcToImage(scope.Fn)
 }
 
-// globalFor returns a global scope for 'image' with the register values of 'scope'.
-func (scope *EvalScope) globalFor(image *Image) *EvalScope {
-	r := *scope
-	r.Regs.StaticBase = image.StaticBase
-	r.Fn = &Function{cu: &compileUnit{image: image}}
-	return &r
-}
-
 // DwarfReader returns the DwarfReader containing the
 // Dwarf information for the target process.
 func (scope *EvalScope) DwarfReader() *reader.Reader {
diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go
index 17dc4081..5bf769fb 100644
--- a/pkg/proc/gdbserial/gdbserver.go
+++ b/pkg/proc/gdbserial/gdbserver.go
@@ -1171,14 +1171,8 @@ func (p *gdbProcess) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
 	return nil, false
 }
 
-func (p *gdbProcess) WriteBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
-	f, l, fn := p.bi.PCToLine(uint64(addr))
-
-	if err := p.conn.setBreakpoint(addr); err != nil {
-		return "", 0, nil, nil, err
-	}
-
-	return f, l, fn, nil, nil
+func (p *gdbProcess) WriteBreakpoint(bp *proc.Breakpoint) error {
+	return p.conn.setBreakpoint(bp.Addr)
 }
 
 func (p *gdbProcess) EraseBreakpoint(bp *proc.Breakpoint) error {
diff --git a/pkg/proc/gdbserial/gdbserver_conn_386.go b/pkg/proc/gdbserial/gdbserver_conn_386.go
new file mode 100644
index 00000000..495998fe
--- /dev/null
+++ b/pkg/proc/gdbserial/gdbserver_conn_386.go
@@ -0,0 +1,15 @@
+//+build 386
+
+package gdbserial
+
+const (
+	regnamePC     = "rip"
+	regnameCX     = "rcx"
+	regnameSP     = "rsp"
+	regnameDX     = "rdx"
+	regnameBP     = "rbp"
+	regnameFsBase = "fs_base"
+	regnameGsBase = "gs_base"
+
+	breakpointKind = 1
+)
diff --git a/pkg/proc/interface.go b/pkg/proc/interface.go
index 90632790..a5076736 100644
--- a/pkg/proc/interface.go
+++ b/pkg/proc/interface.go
@@ -33,7 +33,7 @@ type ProcessInternal interface {
 	Detach(bool) error
 	ContinueOnce() (trapthread Thread, stopReason StopReason, err error)
 
-	WriteBreakpoint(addr uint64) (file string, line int, fn *Function, originalData []byte, err error)
+	WriteBreakpoint(*Breakpoint) error
 	EraseBreakpoint(*Breakpoint) error
 }
 
diff --git a/pkg/proc/native/proc.go b/pkg/proc/native/proc.go
index 4dbaf11d..1083c568 100644
--- a/pkg/proc/native/proc.go
+++ b/pkg/proc/native/proc.go
@@ -203,19 +203,13 @@ func (dbp *nativeProcess) CheckAndClearManualStopRequest() bool {
 	return msr
 }
 
-func (dbp *nativeProcess) WriteBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
-	f, l, fn := dbp.bi.PCToLine(uint64(addr))
-
-	originalData := make([]byte, dbp.bi.Arch.BreakpointSize())
-	_, err := dbp.memthread.ReadMemory(originalData, addr)
+func (dbp *nativeProcess) WriteBreakpoint(bp *proc.Breakpoint) error {
+	bp.OriginalData = make([]byte, dbp.bi.Arch.BreakpointSize())
+	_, err := dbp.memthread.ReadMemory(bp.OriginalData, bp.Addr)
 	if err != nil {
-		return "", 0, nil, nil, err
-	}
-	if err := dbp.writeSoftwareBreakpoint(dbp.memthread, addr); err != nil {
-		return "", 0, nil, nil, err
+		return err
 	}
-
-	return f, l, fn, originalData, nil
+	return dbp.writeSoftwareBreakpoint(dbp.memthread, bp.Addr)
 }
 
 func (dbp *nativeProcess) EraseBreakpoint(bp *proc.Breakpoint) error {
diff --git a/pkg/proc/types.go b/pkg/proc/types.go
index 16d1954e..31bb8489 100644
--- a/pkg/proc/types.go
+++ b/pkg/proc/types.go
@@ -98,6 +98,16 @@ func newLoadDebugInfoMapsContext(bi *BinaryInfo, image *Image, offsetToVersion m
 	return ctxt
 }
 
+func (ctxt *loadDebugInfoMapsContext) lookupAbstractOrigin(bi *BinaryInfo, off dwarf.Offset) int {
+	r, ok := ctxt.abstractOriginTable[off]
+	if !ok {
+		bi.Functions = append(bi.Functions, Function{})
+		r = len(bi.Functions) - 1
+		ctxt.abstractOriginTable[off] = r
+	}
+	return r
+}
+
 // runtimeTypeToDIE returns the DIE corresponding to the runtime._type.
 // This is done in three different ways depending on the version of go.
 // * Before go1.7 the type name is retrieved directly from the runtime._type
diff --git a/pkg/proc/variables.go b/pkg/proc/variables.go
index 3876db08..be836944 100644
--- a/pkg/proc/variables.go
+++ b/pkg/proc/variables.go
@@ -24,9 +24,6 @@ const (
 
 	maxArrayStridePrefetch = 1024 // Maximum size of array stride for which we will prefetch the array contents
 
-	chanRecv = "chan receive"
-	chanSend = "chan send"
-
 	hashTophashEmptyZero = 0 // used by map reading code, indicates an empty cell
 	hashTophashEmptyOne  = 1 // used by map reading code, indicates an empty cell in Go 1.12 and later
 	hashMinTopHashGo111  = 4 // used by map reading code, indicates minimum value of tophash that isn't empty or evacuated, in Go1.11
diff --git a/service/api/prettyprint.go b/service/api/prettyprint.go
index 564bae57..e8ec44df 100644
--- a/service/api/prettyprint.go
+++ b/service/api/prettyprint.go
@@ -421,7 +421,7 @@ func PrettyExamineMemory(address uintptr, memArea []byte, isLittleEndian bool, f
 			}
 		}
 		fmt.Fprintln(w, "")
-		address += uintptr(cols)
+		address += uintptr(cols * colBytes)
 	}
 	w.Flush()
 	return b.String()
diff --git a/service/dap/handles.go b/service/dap/handles.go
index ec9bfe1e..d01baf91 100644
--- a/service/dap/handles.go
+++ b/service/dap/handles.go
@@ -14,6 +14,18 @@ type handlesMap struct {
 	handleToVal map[int]interface{}
 }
 
+type fullyQualifiedVariable struct {
+	*proc.Variable
+	// A way to load this variable by either using all names in the hierarchic
+	// sequence above this variable (most readable when referenced by the UI)
+	// if available or a special expression based on:
+	// https://github.com/go-delve/delve/blob/master/Documentation/api/ClientHowto.md#loading-more-of-a-variable
+	// Empty if the variable cannot or should not be reloaded.
+	fullyQualifiedNameOrExpr string
+	// True if this represents variable scope
+	isScope bool
+}
+
 func newHandlesMap() *handlesMap {
 	return &handlesMap{startHandle, make(map[int]interface{})}
 }
@@ -43,16 +55,16 @@ func newVariablesHandlesMap() *variablesHandlesMap {
 	return &variablesHandlesMap{newHandlesMap()}
 }
 
-func (hs *variablesHandlesMap) create(value *proc.Variable) int {
+func (hs *variablesHandlesMap) create(value *fullyQualifiedVariable) int {
 	return hs.m.create(value)
 }
 
-func (hs *variablesHandlesMap) get(handle int) (*proc.Variable, bool) {
+func (hs *variablesHandlesMap) get(handle int) (*fullyQualifiedVariable, bool) {
 	v, ok := hs.m.get(handle)
 	if !ok {
 		return nil, false
 	}
-	return v.(*proc.Variable), true
+	return v.(*fullyQualifiedVariable), true
 }
 
 func (hs *variablesHandlesMap) reset() {
diff --git a/service/dap/server.go b/service/dap/server.go
index ccf12dc6..7206d133 100644
--- a/service/dap/server.go
+++ b/service/dap/server.go
@@ -832,7 +832,7 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) {
 		s.sendErrorResponse(request.Request, UnableToListArgs, "Unable to list args", err.Error())
 		return
 	}
-	argScope := &proc.Variable{Name: "Arguments", Children: slicePtrVarToSliceVar(args)}
+	argScope := &fullyQualifiedVariable{&proc.Variable{Name: "Arguments", Children: slicePtrVarToSliceVar(args)}, "", true}
 
 	// Retrieve local variables
 	locals, err := s.debugger.LocalVariables(goid, frame, 0, cfg)
@@ -840,7 +840,7 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) {
 		s.sendErrorResponse(request.Request, UnableToListLocals, "Unable to list locals", err.Error())
 		return
 	}
-	locScope := &proc.Variable{Name: "Locals", Children: slicePtrVarToSliceVar(locals)}
+	locScope := &fullyQualifiedVariable{&proc.Variable{Name: "Locals", Children: slicePtrVarToSliceVar(locals)}, "", true}
 
 	// TODO(polina): Annotate shadowed variables
 
@@ -875,10 +875,10 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) {
 			globals[i].Name = strings.TrimPrefix(g.Name, currPkg+".")
 		}
 
-		globScope := &proc.Variable{
+		globScope := &fullyQualifiedVariable{&proc.Variable{
 			Name:     fmt.Sprintf("Globals (package %s)", currPkg),
 			Children: slicePtrVarToSliceVar(globals),
-		}
+		}, currPkg, true}
 		scopeGlobals := dap.Scope{Name: globScope.Name, VariablesReference: s.variableHandles.create(globScope)}
 		scopes = append(scopes, scopeGlobals)
 	}
@@ -915,28 +915,45 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 			// A map will have twice as many children as there are key-value elements.
 			kvIndex := i / 2
 			// Process children in pairs: even indices are map keys, odd indices are values.
-			keyv := &v.Children[i]
-			key, keyref := s.convertVariable(keyv)
-			val, valref := s.convertVariable(&v.Children[i+1])
+			keyv, valv := &v.Children[i], &v.Children[i+1]
+			keyexpr := fmt.Sprintf("(*(*%q)(%#x))", keyv.TypeString(), keyv.Addr)
+			valexpr := fmt.Sprintf("%s[%s]", v.fullyQualifiedNameOrExpr, keyexpr)
+			switch keyv.Kind {
+			// For value expression, use the key value, not the corresponding expression if the key is a scalar.
+			case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128,
+				reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+				reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+				valexpr = fmt.Sprintf("%s[%s]", v.fullyQualifiedNameOrExpr, api.VariableValueAsString(keyv))
+			case reflect.String:
+				if key := constant.StringVal(keyv.Value); keyv.Len == int64(len(key)) { // fully loaded
+					valexpr = fmt.Sprintf("%s[%q]", v.fullyQualifiedNameOrExpr, key)
+				}
+				// TODO(polina): use nil for nil keys of different types
+			}
+			key, keyref := s.convertVariable(keyv, keyexpr)
+			val, valref := s.convertVariable(valv, valexpr)
 			// If key or value or both are scalars, we can use
 			// a single variable to represet key:value format.
 			// Otherwise, we must return separate variables for both.
 			if keyref > 0 && valref > 0 { // Both are not scalars
 				keyvar := dap.Variable{
 					Name:               fmt.Sprintf("[key %d]", kvIndex),
+					EvaluateName:       keyexpr,
 					Value:              key,
 					VariablesReference: keyref,
 				}
 				valvar := dap.Variable{
 					Name:               fmt.Sprintf("[val %d]", kvIndex),
+					EvaluateName:       valexpr,
 					Value:              val,
 					VariablesReference: valref,
 				}
 				children = append(children, keyvar, valvar)
 			} else { // At least one is a scalar
 				kvvar := dap.Variable{
-					Name:  key,
-					Value: val,
+					Name:         key,
+					EvaluateName: valexpr,
+					Value:        val,
 				}
 				if keyref != 0 { // key is a type to be expanded
 					kvvar.Name = fmt.Sprintf("%s(%#x)", kvvar.Name, keyv.Addr) // Make the name unique
@@ -950,35 +967,52 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 	case reflect.Slice, reflect.Array:
 		children = make([]dap.Variable, len(v.Children))
 		for i := range v.Children {
-			c := &v.Children[i]
-			value, varref := s.convertVariable(c)
+			cfqname := fmt.Sprintf("%s[%d]", v.fullyQualifiedNameOrExpr, i)
+			cvalue, cvarref := s.convertVariable(&v.Children[i], cfqname)
 			children[i] = dap.Variable{
 				Name:               fmt.Sprintf("[%d]", i),
-				Value:              value,
-				VariablesReference: varref,
+				EvaluateName:       cfqname,
+				Value:              cvalue,
+				VariablesReference: cvarref,
 			}
 		}
 	default:
 		children = make([]dap.Variable, len(v.Children))
 		for i := range v.Children {
 			c := &v.Children[i]
-			value, variablesReference := s.convertVariable(c)
+			cfqname := fmt.Sprintf("%s.%s", v.fullyQualifiedNameOrExpr, c.Name)
+
+			if strings.HasPrefix(c.Name, "~") || strings.HasPrefix(c.Name, ".") {
+				cfqname = ""
+			} else if v.isScope && v.fullyQualifiedNameOrExpr == "" {
+				cfqname = c.Name
+			} else if v.fullyQualifiedNameOrExpr == "" {
+				cfqname = ""
+			} else if v.Kind == reflect.Interface {
+				cfqname = fmt.Sprintf("%s.(%s)", v.fullyQualifiedNameOrExpr, c.Name) // c is data
+			} else if v.Kind == reflect.Ptr {
+				cfqname = fmt.Sprintf("(*%v)", v.fullyQualifiedNameOrExpr) // c is the nameless pointer value
+			} else if v.Kind == reflect.Complex64 || v.Kind == reflect.Complex128 {
+				cfqname = "" // complex children are not struct fields and can't be accessed directly
+			}
+			cvalue, cvarref := s.convertVariable(c, cfqname)
 			children[i] = dap.Variable{
 				Name:               c.Name,
-				Value:              value,
-				VariablesReference: variablesReference,
+				EvaluateName:       cfqname,
+				Value:              cvalue,
+				VariablesReference: cvarref,
 			}
 		}
 	}
 	response := &dap.VariablesResponse{
 		Response: *newResponse(request.Request),
 		Body:     dap.VariablesResponseBody{Variables: children},
-		// TODO(polina): support evaluateName field
 	}
 	s.send(response)
 }
 
-// convertVariable converts proc.Variable to dap.Variable value and reference.
+// convertVariable converts proc.Variable to dap.Variable value and reference
+// while keeping track of the full qualified name or load expression.
 // Variable reference is used to keep track of the children associated with each
 // variable. It is shared with the host via scopes or evaluate response and is an index
 // into the s.variableHandles map, used to look up variables and their children on
@@ -986,23 +1020,23 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 // variables request can be issued to get the elements of the compound variable. As a
 // custom, a zero reference, reminiscent of a zero pointer, is used to indicate that
 // a scalar variable cannot be "dereferenced" to get its elements (as there are none).
-func (s *Server) convertVariable(v *proc.Variable) (value string, variablesReference int) {
-	return s.convertVariableWithOpts(v, false)
+func (s *Server) convertVariable(v *proc.Variable, qualifiedNameOrExpr string) (value string, variablesReference int) {
+	return s.convertVariableWithOpts(v, qualifiedNameOrExpr, false)
 }
 
 func (s *Server) convertVariableToString(v *proc.Variable) string {
-	val, _ := s.convertVariableWithOpts(v, true)
+	val, _ := s.convertVariableWithOpts(v, "", true)
 	return val
 }
 
-// convertVarialbeWithOpts allows to skip reference generation in case all we need is
+// convertVariableWithOpts allows to skip reference generation in case all we need is
 // a string representation of the variable.
-func (s *Server) convertVariableWithOpts(v *proc.Variable, skipRef bool) (value string, variablesReference int) {
+func (s *Server) convertVariableWithOpts(v *proc.Variable, qualifiedNameOrExpr string, skipRef bool) (value string, variablesReference int) {
 	maybeCreateVariableHandle := func(v *proc.Variable) int {
 		if skipRef {
 			return 0
 		}
-		return s.variableHandles.create(v)
+		return s.variableHandles.create(&fullyQualifiedVariable{v, qualifiedNameOrExpr, false /*not a scope*/})
 	}
 	if v.Unreadable != nil {
 		value = fmt.Sprintf("unreadable <%v>", v.Unreadable)
@@ -1224,7 +1258,7 @@ func (s *Server) onEvaluateRequest(request *dap.EvaluateRequest) {
 			}
 			response.Body = dap.EvaluateResponseBody{
 				Result:             strings.TrimRight(retVarsAsStr, ", "),
-				VariablesReference: s.variableHandles.create(retVarsAsVar),
+				VariablesReference: s.variableHandles.create(&fullyQualifiedVariable{retVarsAsVar, "", false /*not a scope*/}),
 			}
 		}
 	} else { // {expression}
@@ -1233,7 +1267,9 @@ func (s *Server) onEvaluateRequest(request *dap.EvaluateRequest) {
 			s.sendErrorResponseWithOpts(request.Request, UnableToEvaluateExpression, "Unable to evaluate expression", err.Error(), showErrorToUser)
 			return
 		}
-		exprVal, exprRef := s.convertVariable(exprVar)
+		// TODO(polina): as far as I can tell, evaluateName is ignored by vscode for expression variables.
+		// Should it be skipped alltogether for all levels?
+		exprVal, exprRef := s.convertVariable(exprVar, fmt.Sprintf("(%s)", request.Arguments.Expression))
 		response.Body = dap.EvaluateResponseBody{Result: exprVal, VariablesReference: exprRef}
 	}
 	s.send(response)


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ba12c1d2..1e94da3b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,10 +10,6 @@ jobs:
         include:
           - go: 1.15
             os: macos-latest
-          - go: 1.14
-            os: ubuntu-latest
-          - go: 1.13
-            os: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
       - uses: actions/setup-go@v1
diff --git a/_scripts/test_linux.sh b/_scripts/test_linux.sh
new file mode 100755
index 00000000..387a1345
--- /dev/null
+++ b/_scripts/test_linux.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+set -e
+set -x
+
+apt-get -qq update
+apt-get install -y dwz wget make git gcc curl jq
+dwz --version
+
+version=$1
+arch=$2
+
+function getgo {
+	export GOROOT=/usr/local/go/$1
+	if [ ! -d "$GOROOT" ]; then
+		wget -q https://dl.google.com/go/"$1".linux-"${arch}".tar.gz
+		mkdir -p /usr/local/go
+		tar -C /usr/local/go -xzf "$1".linux-"${arch}".tar.gz
+		mv -f /usr/local/go/go "$GOROOT"
+	fi
+}
+
+if [ "$version" = "gotip" ]; then
+	exit 0
+	echo Building Go from tip
+	getgo $(curl https://golang.org/VERSION?m=text)
+	export GOROOT_BOOTSTRAP=$GOROOT
+	export GOROOT=/usr/local/go/go-tip
+	git clone https://go.googlesource.com/go /usr/local/go/go-tip
+	cd /usr/local/go/go-tip/src
+	./make.bash
+	cd -
+else
+	echo Finding latest patch version for $version
+	version=$(curl 'https://golang.org/dl/?mode=json&include=all' | jq '.[].version' --raw-output | egrep ^$version'($|\.|beta|rc)' | head -1)
+	echo "Go $version on $arch"
+	getgo $version
+fi
+
+
+GOPATH=$(pwd)/go
+export GOPATH
+export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
+go version
+
+uname -a
+echo "$PATH"
+echo "$GOROOT"
+echo "$GOPATH"
+cd delve
+make test
diff --git a/_scripts/test_windows.ps1 b/_scripts/test_windows.ps1
new file mode 100644
index 00000000..2011a705
--- /dev/null
+++ b/_scripts/test_windows.ps1
@@ -0,0 +1,69 @@
+param (
+    [Parameter(Mandatory = $true)][string]$version,
+    [Parameter(Mandatory = $true)][string]$arch
+)
+
+# Install MinGW.
+if (-Not(Test-Path "C:\mingw64"))
+{
+    $file = "x86_64-4.9.2-release-win32-seh-rt_v4-rev3.7z"
+    $url = "https://bintray.com/artifact/download/drewwells/generic/$file"
+    Invoke-WebRequest -UserAgent wget -Uri $url -OutFile $file
+    &7z x -oC:\ $file > $null
+}
+
+# Install Procdump
+if (-Not(Test-Path "C:\procdump"))
+{
+    mkdir C:\procdump
+    Invoke-WebRequest -UserAgent wget -Uri https://download.sysinternals.com/files/Procdump.zip -OutFile C:\procdump\procdump.zip
+    &7z x -oC:\procdump\ C:\procdump\procdump.zip > $null
+}
+
+$env:PATH += ";C:\procdump;C:\mingw64\bin"
+
+function GetGo($version) {
+    $env:GOROOT = "C:\go\$version"
+    if (-Not(Test-Path $env:GOROOT))
+    {
+        $file = "$version.windows-$arch.zip"
+        $url = "https://dl.google.com/go/$file"
+        Invoke-WebRequest -UserAgent wget -Uri $url -OutFile $file
+        &7z x -oC:\go $file > $null
+        Move-Item -Path C:\go\go -Destination $env:GOROOT -force
+    }
+}
+
+if ($version -eq "gotip") {
+    Exit 0
+    $latest = Invoke-WebRequest -Uri https://golang.org/VERSION?m=text -UseBasicParsing | Select-Object -ExpandProperty Content
+    GetGo $latest
+    $env:GOROOT_BOOTSTRAP = $env:GOROOT
+    $env:GOROOT = "C:\go\go-tip"
+    Write-Host "Building Go with GOROOT_BOOTSTRAP $env:GOROOT_BOOTSTRAP"
+    if (-Not(Test-Path $env:GOROOT)) {
+        git clone https://go.googlesource.com/go C:\go\go-tip
+        Push-Location -Path C:\go\go-tip\src
+    } else {
+        Push-Location -Path C:\go\go-tip\src
+        git pull
+    }
+    .\make.bat
+    Pop-Location
+} else {
+    # Install Go
+    Write-Host "Finding latest patch version for $version"
+    $version = Invoke-WebRequest -Uri 'https://golang.org/dl/?mode=json&include=all' -UseBasicParsing | foreach {$_.Content} | ConvertFrom-Json | foreach {$_.version} | Select-String -Pattern "^$version($|\.|beta|rc)" | Select-Object -First 1 | foreach {$_.Line}
+    Write-Host "Go $version on $arch"
+    GetGo $version
+}
+
+$env:GOPATH = "C:\gopath"
+$env:PATH += ";$env:GOROOT\bin;$env:GOPATH\bin"
+Write-Host $env:PATH
+Write-Host $env:GOROOT
+Write-Host $env:GOPATH
+
+go version
+go env
+mingw32-make test
diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go
index e5e58b7f..8a9874a6 100644
--- a/cmd/dlv/dlv_test.go
+++ b/cmd/dlv/dlv_test.go
@@ -329,12 +329,17 @@ func TestRedirect(t *testing.T) {
 func checkAutogenDoc(t *testing.T, filename, gencommand string, generated []byte) {
 	saved := slurpFile(t, filepath.Join(projectRoot(), filename))
 
+	saved = bytes.ReplaceAll(saved, []byte("\r\n"), []byte{'\n'})
+	generated = bytes.ReplaceAll(generated, []byte("\r\n"), []byte{'\n'})
+
 	if len(saved) != len(generated) {
+		t.Logf("generated %q saved %q\n", generated, saved)
 		t.Fatalf("%s: needs to be regenerated; run %s", filename, gencommand)
 	}
 
 	for i := range saved {
 		if saved[i] != generated[i] {
+			t.Logf("generated %q saved %q\n", generated, saved)
 			t.Fatalf("%s: needs to be regenerated; run %s", filename, gencommand)
 		}
 	}
diff --git a/pkg/proc/dwarf_expr_test.go b/pkg/proc/dwarf_expr_test.go
index f5e34173..0ce6c83e 100644
--- a/pkg/proc/dwarf_expr_test.go
+++ b/pkg/proc/dwarf_expr_test.go
@@ -353,3 +353,43 @@ func TestNestedCompileUnts(t *testing.T) {
 		t.Errorf("expected 2 variables, got %d", n)
 	}
 }
+
+func TestAbstractOriginDefinedAfterUse(t *testing.T) {
+	// Tests that an abstract origin entry can appear after its uses.
+	dwb := dwarfbuilder.New()
+	dwb.AddCompileUnit("main", 0x0)
+
+	// Concrete implementation
+	dwb.TagOpen(dwarf.TagSubprogram, "")
+	originRef1 := dwb.Attr(dwarf.AttrAbstractOrigin, dwarf.Offset(0))
+	dwb.Attr(dwarf.AttrLowpc, dwarfbuilder.Address(0x40100))
+	dwb.Attr(dwarf.AttrHighpc, dwarfbuilder.Address(0x41000))
+	dwb.TagClose()
+
+	// Inlined call
+	dwb.AddSubprogram("callingFn", 0x41100, 0x42000)
+	dwb.TagOpen(dwarf.TagInlinedSubroutine, "")
+	originRef2 := dwb.Attr(dwarf.AttrAbstractOrigin, dwarf.Offset(0))
+	dwb.Attr(dwarf.AttrLowpc, dwarfbuilder.Address(0x41150))
+	dwb.Attr(dwarf.AttrHighpc, dwarfbuilder.Address(0x41155))
+	dwb.Attr(dwarf.AttrCallFile, uint8(1))
+	dwb.Attr(dwarf.AttrCallLine, uint8(1))
+	dwb.TagClose()
+	dwb.TagClose()
+
+	// Abstract origin
+	abstractOriginOff := dwb.TagOpen(dwarf.TagSubprogram, "inlinedFn")
+	dwb.Attr(dwarf.AttrInline, uint8(1))
+	dwb.TagClose()
+
+	dwb.TagClose()
+
+	dwb.PatchOffset(originRef1, abstractOriginOff)
+	dwb.PatchOffset(originRef2, abstractOriginOff)
+
+	bi, _ := fakeBinaryInfo(t, dwb)
+	fn := bi.PCToFunc(0x40100)
+	if fn == nil {
+		t.Fatalf("could not find concrete instance of inlined function")
+	}
+}
diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go
index 8a410165..3ea5c6e7 100644
--- a/pkg/proc/proc_test.go
+++ b/pkg/proc/proc_test.go
@@ -1302,23 +1302,9 @@ func TestFrameEvaluation(t *testing.T) {
 			found[vval] = true
 		}
 
-		firsterr := false
-		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) {
-			// We try to make sure that all goroutines are stopped at a sensible place
-			// before reading their stacktrace, but due to the nature of the test
-			// program there is no guarantee that we always find them in a reasonable
-			// state.
-			// Asynchronous preemption in Go 1.14 exacerbates this problem, to avoid
-			// unnecessary flakiness allow a single goroutine to be in a bad state.
-			firsterr = true
-		}
 		for i := range found {
 			if !found[i] {
-				if firsterr {
-					firsterr = false
-				} else {
-					t.Fatalf("Goroutine %d not found\n", i)
-				}
+				t.Fatalf("Goroutine %d not found\n", i)
 			}
 		}
 
diff --git a/service/dap/server_test.go b/service/dap/server_test.go
index e80a2ba1..8c71bc63 100644
--- a/service/dap/server_test.go
+++ b/service/dap/server_test.go
@@ -492,8 +492,8 @@ func TestPreSetBreakpoint(t *testing.T) {
 		client.VariablesRequest(1000) // Arguments
 		args := client.ExpectVariablesResponse(t)
 		expectChildren(t, args, "Arguments", 2)
-		expectVarExact(t, args, 0, "y", "0", noChildren)
-		expectVarExact(t, args, 1, "~r1", "0", noChildren)
+		expectVarExact(t, args, 0, "y", "y", "0", noChildren)
+		expectVarExact(t, args, 1, "~r1", "", "0", noChildren)
 
 		client.VariablesRequest(1001) // Locals
 		locals := client.ExpectVariablesResponse(t)
@@ -580,11 +580,12 @@ func expectChildren(t *testing.T, got *dap.VariablesResponse, parentName string,
 // expectVar is a helper for verifying the values within a VariablesResponse.
 //     i - index of the variable within VariablesRespose.Body.Variables array (-1 will search all vars for a match)
 //     name - name of the variable
+//     evalName - fully qualified variable name or alternative expression to load this variable
 //     value - the value of the variable
-//     useExactMatch - true if name and value are to be compared to exactly, false if to be used as regex
+//     useExactMatch - true if name, evalName and value are to be compared to exactly, false if to be used as regex
 //     hasRef - true if the variable should have children and therefore a non-0 variable reference
 //     ref - reference to retrieve children of this variable (0 if none)
-func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, value string, useExactMatch, hasRef bool) (ref int) {
+func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, useExactMatch, hasRef bool) (ref int) {
 	t.Helper()
 	if len(got.Body.Variables) <= i {
 		t.Errorf("\ngot  len=%d (children=%#v)\nwant len>%d", len(got.Body.Variables), got.Body.Variables, i)
@@ -613,6 +614,15 @@ func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, value stri
 	if !matchedName || (goti.VariablesReference > 0) != hasRef {
 		t.Errorf("\ngot  %#v\nwant Name=%q hasRef=%t", goti, name, hasRef)
 	}
+	matchedEvalName := false
+	if useExactMatch {
+		matchedEvalName = (goti.EvaluateName == evalName)
+	} else {
+		matchedEvalName, _ = regexp.MatchString(evalName, goti.EvaluateName)
+	}
+	if !matchedEvalName {
+		t.Errorf("\ngot  %q\nwant EvaluateName=%q", goti.EvaluateName, evalName)
+	}
 	matchedValue := false
 	if useExactMatch {
 		matchedValue = (goti.Value == value)
@@ -626,15 +636,31 @@ func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, value stri
 }
 
 // expectVarExact is a helper like expectVar that matches value exactly.
-func expectVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, value string, hasRef bool) (ref int) {
+func expectVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, hasRef bool) (ref int) {
+	t.Helper()
+	return expectVar(t, got, i, name, evalName, value, true, hasRef)
+}
+
+// expectVarRegex is a helper like expectVar that treats value, evalName or name as a regex.
+func expectVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, hasRef bool) (ref int) {
 	t.Helper()
-	return expectVar(t, got, i, name, value, true, hasRef)
+	return expectVar(t, got, i, name, evalName, value, false, hasRef)
 }
 
-// expectVarRegex is a helper like expectVar that treats name and value as a regex.
-func expectVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, value string, hasRef bool) (ref int) {
+// validateEvaluateName issues an evaluate request with evaluateName of a variable and
+// confirms that it succeeds and returns the same variable record as the original.
+func validateEvaluateName(t *testing.T, client *daptest.Client, got *dap.VariablesResponse, i int) {
 	t.Helper()
-	return expectVar(t, got, i, name, value, false, hasRef)
+	original := got.Body.Variables[i]
+	client.EvaluateRequest(original.EvaluateName, 1000, "this context will be ignored")
+	validated := client.ExpectEvaluateResponse(t)
+	if original.VariablesReference == 0 && validated.Body.VariablesReference != 0 ||
+		original.VariablesReference != 0 && validated.Body.VariablesReference == 0 {
+		t.Errorf("\ngot  varref=%d\nwant %d", validated.Body.VariablesReference, original.VariablesReference)
+	}
+	if original.Value != validated.Body.Result {
+		t.Errorf("\ngot  value=%q\nwant %q", validated.Body.Result, original.Value)
+	}
 }
 
 // TestStackTraceRequest executes to a breakpoint and tests different
@@ -745,21 +771,23 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					client.VariablesRequest(1000)
 					args := client.ExpectVariablesResponse(t)
 					expectChildren(t, args, "Arguments", 2)
-					expectVarExact(t, args, 0, "baz", `"bazburzum"`, noChildren)
-					ref := expectVarExact(t, args, 1, "bar", `<main.FooBar>`, hasChildren)
+					expectVarExact(t, args, 0, "baz", "baz", `"bazburzum"`, noChildren)
+					ref := expectVarExact(t, args, 1, "bar", "bar", `<main.FooBar>`, hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						bar := client.ExpectVariablesResponse(t)
 						expectChildren(t, bar, "bar", 2)
-						expectVarExact(t, bar, 0, "Baz", "10", noChildren)
-						expectVarExact(t, bar, 1, "Bur", `"lorem"`, noChildren)
+						expectVarExact(t, bar, 0, "Baz", "bar.Baz", "10", noChildren)
+						expectVarExact(t, bar, 1, "Bur", "bar.Bur", `"lorem"`, noChildren)
+						validateEvaluateName(t, client, bar, 0)
+						validateEvaluateName(t, client, bar, 1)
 					}
 
 					// Globals
 
 					client.VariablesRequest(1002)
 					globals := client.ExpectVariablesResponse(t)
-					expectVarExact(t, globals, 0, "p1", "10", noChildren)
+					expectVarExact(t, globals, 0, "p1", "main.p1", "10", noChildren)
 
 					// Locals
 
@@ -768,74 +796,75 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					expectChildren(t, locals, "Locals", 30)
 
 					// reflect.Kind == Bool
-					expectVarExact(t, locals, -1, "b1", "true", noChildren)
-					expectVarExact(t, locals, -1, "b2", "false", noChildren)
+					expectVarExact(t, locals, -1, "b1", "b1", "true", noChildren)
+					expectVarExact(t, locals, -1, "b2", "b2", "false", noChildren)
 					// reflect.Kind == Int
-					expectVarExact(t, locals, -1, "a2", "6", noChildren)
-					expectVarExact(t, locals, -1, "neg", "-1", noChildren)
+					expectVarExact(t, locals, -1, "a2", "a2", "6", noChildren)
+					expectVarExact(t, locals, -1, "neg", "neg", "-1", noChildren)
 					// reflect.Kind == Int8
-					expectVarExact(t, locals, -1, "i8", "1", noChildren)
+					expectVarExact(t, locals, -1, "i8", "i8", "1", noChildren)
 					// reflect.Kind == Int16 - see testvariables2
 					// reflect.Kind == Int32 - see testvariables2
 					// reflect.Kind == Int64 - see testvariables2
 					// reflect.Kind == Uint
 					// reflect.Kind == Uint8
-					expectVarExact(t, locals, -1, "u8", "255", noChildren)
+					expectVarExact(t, locals, -1, "u8", "u8", "255", noChildren)
 					// reflect.Kind == Uint16
-					expectVarExact(t, locals, -1, "u16", "65535", noChildren)
+					expectVarExact(t, locals, -1, "u16", "u16", "65535", noChildren)
 					// reflect.Kind == Uint32
-					expectVarExact(t, locals, -1, "u32", "4294967295", noChildren)
+					expectVarExact(t, locals, -1, "u32", "u32", "4294967295", noChildren)
 					// reflect.Kind == Uint64
-					expectVarExact(t, locals, -1, "u64", "18446744073709551615", noChildren)
+					expectVarExact(t, locals, -1, "u64", "u64", "18446744073709551615", noChildren)
 					// reflect.Kind == Uintptr
-					expectVarExact(t, locals, -1, "up", "5", noChildren)
+					expectVarExact(t, locals, -1, "up", "up", "5", noChildren)
 					// reflect.Kind == Float32
-					expectVarExact(t, locals, -1, "f32", "1.2", noChildren)
+					expectVarExact(t, locals, -1, "f32", "f32", "1.2", noChildren)
 					// reflect.Kind == Float64
-					expectVarExact(t, locals, -1, "a3", "7.23", noChildren)
+					expectVarExact(t, locals, -1, "a3", "a3", "7.23", noChildren)
 					// reflect.Kind == Complex64
-					ref = expectVarExact(t, locals, -1, "c64", "(1 + 2i)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "c64", "c64", "(1 + 2i)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						c64 := client.ExpectVariablesResponse(t)
 						expectChildren(t, c64, "c64", 2)
-						expectVarExact(t, c64, 0, "real", "1", noChildren)
-						expectVarExact(t, c64, 1, "imaginary", "2", noChildren)
+						expectVarExact(t, c64, 0, "real", "", "1", noChildren)
+						expectVarExact(t, c64, 1, "imaginary", "", "2", noChildren)
 					}
 					// reflect.Kind == Complex128
-					ref = expectVarExact(t, locals, -1, "c128", "(2 + 3i)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "c128", "c128", "(2 + 3i)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						c128 := client.ExpectVariablesResponse(t)
 						expectChildren(t, c128, "c128", 2)
-						expectVarExact(t, c128, 0, "real", "2", noChildren)
-						expectVarExact(t, c128, 1, "imaginary", "3", noChildren)
+						expectVarExact(t, c128, 0, "real", "", "2", noChildren)
+						expectVarExact(t, c128, 1, "imaginary", "", "3", noChildren)
 					}
 					// reflect.Kind == Array
-					ref = expectVarExact(t, locals, -1, "a4", "<[2]int>", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a4", "a4", "<[2]int>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a4 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a4, "a4", 2)
-						expectVarExact(t, a4, 0, "[0]", "1", noChildren)
-						expectVarExact(t, a4, 1, "[1]", "2", noChildren)
+						expectVarExact(t, a4, 0, "[0]", "a4[0]", "1", noChildren)
+						expectVarExact(t, a4, 1, "[1]", "a4[1]", "2", noChildren)
 					}
-					ref = expectVarExact(t, locals, -1, "a11", "<[3]main.FooBar>", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a11", "a11", "<[3]main.FooBar>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a11 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a11, "a11", 3)
-						expectVarExact(t, a11, 0, "[0]", "<main.FooBar>", hasChildren)
-						ref = expectVarExact(t, a11, 1, "[1]", "<main.FooBar>", hasChildren)
+						expectVarExact(t, a11, 0, "[0]", "a11[0]", "<main.FooBar>", hasChildren)
+						ref = expectVarExact(t, a11, 1, "[1]", "a11[1]", "<main.FooBar>", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a11_1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, a11_1, "a11[1]", 2)
-							expectVarExact(t, a11_1, 0, "Baz", "2", noChildren)
-							expectVarExact(t, a11_1, 1, "Bur", `"b"`, noChildren)
-
+							expectVarExact(t, a11_1, 0, "Baz", "a11[1].Baz", "2", noChildren)
+							expectVarExact(t, a11_1, 1, "Bur", "a11[1].Bur", `"b"`, noChildren)
+							validateEvaluateName(t, client, a11_1, 0)
+							validateEvaluateName(t, client, a11_1, 1)
 						}
-						expectVarExact(t, a11, 2, "[2]", "<main.FooBar>", hasChildren)
+						expectVarExact(t, a11, 2, "[2]", "a11[2]", "<main.FooBar>", hasChildren)
 					}
 
 					// reflect.Kind == Chan - see testvariables2
@@ -843,87 +872,96 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					// reflect.Kind == Interface - see testvariables2
 					// reflect.Kind == Map - see testvariables2
 					// reflect.Kind == Ptr
-					ref = expectVarRegex(t, locals, -1, "a7", `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
+					ref = expectVarRegex(t, locals, -1, "a7", "a7", `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a7 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a7, "a7", 1)
-						ref = expectVarExact(t, a7, 0, "", "<main.FooBar>", hasChildren)
+						ref = expectVarExact(t, a7, 0, "", "(*a7)", "<main.FooBar>", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a7val := client.ExpectVariablesResponse(t)
 							expectChildren(t, a7val, "*a7", 2)
-							expectVarExact(t, a7val, 0, "Baz", "5", noChildren)
-							expectVarExact(t, a7val, 1, "Bur", `"strum"`, noChildren)
+							expectVarExact(t, a7val, 0, "Baz", "(*a7).Baz", "5", noChildren)
+							expectVarExact(t, a7val, 1, "Bur", "(*a7).Bur", `"strum"`, noChildren)
+							validateEvaluateName(t, client, a7val, 0)
+							validateEvaluateName(t, client, a7val, 1)
 						}
 					}
 					// TODO(polina): how to test for "nil" (without type) and "void"?
-					expectVarExact(t, locals, -1, "a9", "nil <*main.FooBar>", noChildren)
+					expectVarExact(t, locals, -1, "a9", "a9", "nil <*main.FooBar>", noChildren)
 					// reflect.Kind == Slice
-					ref = expectVarExact(t, locals, -1, "a5", "<[]int> (length: 5, cap: 5)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a5", "a5", "<[]int> (length: 5, cap: 5)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a5 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a5, "a5", 5)
-						expectVarExact(t, a5, 0, "[0]", "1", noChildren)
-						expectVarExact(t, a5, 4, "[4]", "5", noChildren)
+						expectVarExact(t, a5, 0, "[0]", "a5[0]", "1", noChildren)
+						expectVarExact(t, a5, 4, "[4]", "a5[4]", "5", noChildren)
+						validateEvaluateName(t, client, a5, 0)
+						validateEvaluateName(t, client, a5, 1)
 					}
-					ref = expectVarExact(t, locals, -1, "a12", "<[]main.FooBar> (length: 2, cap: 2)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a12", "a12", "<[]main.FooBar> (length: 2, cap: 2)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a12 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a12, "a12", 2)
-						expectVarExact(t, a12, 0, "[0]", "<main.FooBar>", hasChildren)
-						ref = expectVarExact(t, a12, 1, "[1]", "<main.FooBar>", hasChildren)
+						expectVarExact(t, a12, 0, "[0]", "a12[0]", "<main.FooBar>", hasChildren)
+						ref = expectVarExact(t, a12, 1, "[1]", "a12[1]", "<main.FooBar>", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a12_1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, a12_1, "a12[1]", 2)
-							expectVarExact(t, a12_1, 0, "Baz", "5", noChildren)
-							expectVarExact(t, a12_1, 1, "Bur", `"e"`, noChildren)
+							expectVarExact(t, a12_1, 0, "Baz", "a12[1].Baz", "5", noChildren)
+							expectVarExact(t, a12_1, 1, "Bur", "a12[1].Bur", `"e"`, noChildren)
+							validateEvaluateName(t, client, a12_1, 0)
+							validateEvaluateName(t, client, a12_1, 1)
 						}
 					}
-					ref = expectVarExact(t, locals, -1, "a13", "<[]*main.FooBar> (length: 3, cap: 3)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a13", "a13", "<[]*main.FooBar> (length: 3, cap: 3)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a13 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a13, "a13", 3)
-						expectVarRegex(t, a13, 0, `\[0\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
-						expectVarRegex(t, a13, 1, `\[1\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
-						ref = expectVarRegex(t, a13, 2, `\[2\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
+						expectVarRegex(t, a13, 0, `\[0\]`, `a13\[0\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
+						expectVarRegex(t, a13, 1, `\[1\]`, `a13\[1\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
+						ref = expectVarRegex(t, a13, 2, `\[2\]`, `a13\[2\]`, `<\*main\.FooBar>\(0x[0-9a-f]+\)`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a13_2 := client.ExpectVariablesResponse(t)
 							expectChildren(t, a13_2, "a13[2]", 1)
-							ref = expectVarExact(t, a13_2, 0, "", "<main.FooBar>", hasChildren)
+							ref = expectVarExact(t, a13_2, 0, "", "(*a13[2])", "<main.FooBar>", hasChildren)
+							validateEvaluateName(t, client, a13_2, 0)
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								val := client.ExpectVariablesResponse(t)
 								expectChildren(t, val, "*a13[2]", 2)
-								expectVarExact(t, val, 0, "Baz", "8", noChildren)
-								expectVarExact(t, val, 1, "Bur", `"h"`, noChildren)
+								expectVarExact(t, val, 0, "Baz", "(*a13[2]).Baz", "8", noChildren)
+								expectVarExact(t, val, 1, "Bur", "(*a13[2]).Bur", `"h"`, noChildren)
+								validateEvaluateName(t, client, val, 0)
+								validateEvaluateName(t, client, val, 1)
 							}
 						}
 					}
 					// reflect.Kind == String
-					expectVarExact(t, locals, -1, "a1", `"foofoofoofoofoofoo"`, noChildren)
-					expectVarExact(t, locals, -1, "a10", `"ofo"`, noChildren)
+					expectVarExact(t, locals, -1, "a1", "a1", `"foofoofoofoofoofoo"`, noChildren)
+					expectVarExact(t, locals, -1, "a10", "a10", `"ofo"`, noChildren)
 					// reflect.Kind == Struct
-					ref = expectVarExact(t, locals, -1, "a6", "<main.FooBar>", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a6", "a6", "<main.FooBar>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a6 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a6, "a6", 2)
-						expectVarExact(t, a6, 0, "Baz", "8", noChildren)
-						expectVarExact(t, a6, 1, "Bur", `"word"`, noChildren)
+						expectVarExact(t, a6, 0, "Baz", "a6.Baz", "8", noChildren)
+						expectVarExact(t, a6, 1, "Bur", "a6.Bur", `"word"`, noChildren)
 					}
-					ref = expectVarExact(t, locals, -1, "a8", "<main.FooBar2>", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a8", "a8", "<main.FooBar2>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a8 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a8, "a8", 2)
-						expectVarExact(t, a8, 0, "Bur", "10", noChildren)
-						expectVarExact(t, a8, 1, "Baz", `"feh"`, noChildren)
+						expectVarExact(t, a8, 0, "Bur", "a8.Bur", "10", noChildren)
+						expectVarExact(t, a8, 1, "Baz", "a8.Baz", `"feh"`, noChildren)
 					}
 					// reflect.Kind == UnsafePointer - see testvariables2
 				},
@@ -955,11 +993,11 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
 					expectChildren(t, locals, "Locals", 1)
-					expectVarExact(t, locals, -1, "a1", `"bur"`, noChildren)
+					expectVarExact(t, locals, -1, "a1", "a1", `"bur"`, noChildren)
 
 					client.VariablesRequest(1002) // Globals
 					globals := client.ExpectVariablesResponse(t)
-					expectVarExact(t, globals, 0, "p1", "10", noChildren)
+					expectVarExact(t, globals, 0, "p1", "main.p1", "10", noChildren)
 
 					client.VariablesRequest(7777)
 					erres = client.ExpectErrorResponse(t)
@@ -1025,13 +1063,13 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					// reflect.Kind == Bool - see testvariables
 					// reflect.Kind == Int - see testvariables
 					// reflect.Kind == Int8
-					expectVarExact(t, locals, -1, "ni8", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni8", "ni8", "-5", noChildren)
 					// reflect.Kind == Int16
-					expectVarExact(t, locals, -1, "ni16", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni16", "ni16", "-5", noChildren)
 					// reflect.Kind == Int32
-					expectVarExact(t, locals, -1, "ni32", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni32", "ni32", "-5", noChildren)
 					// reflect.Kind == Int64
-					expectVarExact(t, locals, -1, "ni64", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni64", "ni64", "-5", noChildren)
 					// reflect.Kind == Uint
 					// reflect.Kind == Uint8 - see testvariables
 					// reflect.Kind == Uint16 - see testvariables
@@ -1040,150 +1078,178 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					// reflect.Kind == Uintptr - see testvariables
 					// reflect.Kind == Float32 - see testvariables
 					// reflect.Kind == Float64
-					expectVarExact(t, locals, -1, "pinf", "+Inf", noChildren)
-					expectVarExact(t, locals, -1, "ninf", "-Inf", noChildren)
-					expectVarExact(t, locals, -1, "nan", "NaN", noChildren)
+					expectVarExact(t, locals, -1, "pinf", "pinf", "+Inf", noChildren)
+					expectVarExact(t, locals, -1, "ninf", "ninf", "-Inf", noChildren)
+					expectVarExact(t, locals, -1, "nan", "nan", "NaN", noChildren)
 					// reflect.Kind == Complex64 - see testvariables
 					// reflect.Kind == Complex128 - see testvariables
 					// reflect.Kind == Array
-					expectVarExact(t, locals, -1, "a0", "<[0]int>", noChildren)
+					expectVarExact(t, locals, -1, "a0", "a0", "<[0]int>", noChildren)
 					// reflect.Kind == Chan
-					ref := expectVarExact(t, locals, -1, "ch1", "<chan int>", hasChildren)
+					ref := expectVarExact(t, locals, -1, "ch1", "ch1", "<chan int>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						ch1 := client.ExpectVariablesResponse(t)
 						expectChildren(t, ch1, "ch1", 11)
-						expectVarExact(t, ch1, 0, "qcount", "4", noChildren)
-						expectVarExact(t, ch1, 10, "lock", "<runtime.mutex>", hasChildren)
+						expectVarExact(t, ch1, 0, "qcount", "ch1.qcount", "4", noChildren)
+						expectVarExact(t, ch1, 10, "lock", "ch1.lock", "<runtime.mutex>", hasChildren)
+						validateEvaluateName(t, client, ch1, 0)
+						validateEvaluateName(t, client, ch1, 10)
 					}
-					expectVarExact(t, locals, -1, "chnil", "nil <chan int>", noChildren)
+					expectVarExact(t, locals, -1, "chnil", "chnil", "nil <chan int>", noChildren)
 					// reflect.Kind == Func
-					expectVarExact(t, locals, -1, "fn1", "main.afunc", noChildren)
-					expectVarExact(t, locals, -1, "fn2", "<main.functype>", noChildren)
+					expectVarExact(t, locals, -1, "fn1", "fn1", "main.afunc", noChildren)
+					expectVarExact(t, locals, -1, "fn2", "fn2", "<main.functype>", noChildren)
 					// reflect.Kind == Interface
-					expectVarExact(t, locals, -1, "ifacenil", "nil <interface {}>", noChildren)
-					ref = expectVarExact(t, locals, -1, "iface2", "<interface {}(string)>", hasChildren)
+					expectVarExact(t, locals, -1, "ifacenil", "ifacenil", "nil <interface {}>", noChildren)
+					ref = expectVarExact(t, locals, -1, "iface2", "iface2", "<interface {}(string)>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						iface2 := client.ExpectVariablesResponse(t)
 						expectChildren(t, iface2, "iface2", 1)
-						expectVarExact(t, iface2, 0, "data", `"test"`, noChildren)
+						expectVarExact(t, iface2, 0, "data", "iface2.(data)", `"test"`, noChildren)
+						validateEvaluateName(t, client, iface2, 0)
 					}
-					ref = expectVarExact(t, locals, -1, "iface4", "<interface {}([]go/constant.Value)>", hasChildren)
+					ref = expectVarExact(t, locals, -1, "iface4", "iface4", "<interface {}([]go/constant.Value)>", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						iface4 := client.ExpectVariablesResponse(t)
 						expectChildren(t, iface4, "iface4", 1)
-						ref = expectVarExact(t, iface4, 0, "data", "<[]go/constant.Value> (length: 1, cap: 1)", hasChildren)
+						ref = expectVarExact(t, iface4, 0, "data", "iface4.(data)", "<[]go/constant.Value> (length: 1, cap: 1)", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							iface4data := client.ExpectVariablesResponse(t)
 							expectChildren(t, iface4data, "iface4.data", 1)
-							expectVarExact(t, iface4data, 0, "[0]", "<go/constant.Value(go/constant.int64Val)>", hasChildren)
-
+							ref = expectVarExact(t, iface4data, 0, "[0]", "iface4.(data)[0]", "<go/constant.Value(go/constant.int64Val)>", hasChildren)
+							if ref > 0 {
+								client.VariablesRequest(ref)
+								iface4data0 := client.ExpectVariablesResponse(t)
+								expectChildren(t, iface4data0, "iface4.data[0]", 1)
+								expectVarExact(t, iface4data0, 0, "data", "iface4.(data)[0].(data)", "4", noChildren)
+								validateEvaluateName(t, client, iface4data0, 0)
+							}
 						}
 					}
-					expectVarExact(t, locals, -1, "errnil", "nil <error>", noChildren)
-					expectVarExact(t, locals, -1, "err1", "<error(*main.astruct)>", hasChildren)
+					expectVarExact(t, locals, -1, "errnil", "errnil", "nil <error>", noChildren)
+					ref = expectVarExact(t, locals, -1, "err1", "err1", "<error(*main.astruct)>", hasChildren)
+					if ref > 0 {
+						client.VariablesRequest(ref)
+						err1 := client.ExpectVariablesResponse(t)
+						expectChildren(t, err1, "err1", 1)
+						expectVarRegex(t, err1, 0, "data", `err1\.\(data\)`, `<\*main\.astruct>\(0x[0-9a-f]+\)`, hasChildren)
+						validateEvaluateName(t, client, err1, 0)
+					}
 					// reflect.Kind == Map
-					expectVarExact(t, locals, -1, "mnil", "nil <map[string]main.astruct>", noChildren)
-					ref = expectVarExact(t, locals, -1, "m2", "<map[int]*main.astruct> (length: 1)", hasChildren)
+					expectVarExact(t, locals, -1, "mnil", "mnil", "nil <map[string]main.astruct>", noChildren)
+					// key - scalar, value - compound
+					ref = expectVarExact(t, locals, -1, "m2", "m2", "<map[int]*main.astruct> (length: 1)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m2 := client.ExpectVariablesResponse(t)
-						expectChildren(t, m2, "m2", 1)
-						ref = expectVarRegex(t, m2, 0, "1", `<\*main\.astruct>\(0x[0-9a-f]+\)`, hasChildren)
+						expectChildren(t, m2, "m2", 1) // each key-value represented by a single child
+						ref = expectVarRegex(t, m2, 0, "1", `m2\[1\]`, `<\*main\.astruct>\(0x[0-9a-f]+\)`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
-							m2_1 := client.ExpectVariablesResponse(t)
-							expectChildren(t, m2_1, "m2[1]", 1)
-							ref = expectVarExact(t, m2_1, 0, "", "<main.astruct>", hasChildren)
+							m2kv1 := client.ExpectVariablesResponse(t)
+							expectChildren(t, m2kv1, "m2[1]", 1)
+							ref = expectVarExact(t, m2kv1, 0, "", "(*m2[1])", "<main.astruct>", hasChildren)
 							if ref > 0 {
 								client.VariablesRequest(ref)
-								m2_1val := client.ExpectVariablesResponse(t)
-								expectChildren(t, m2_1val, "*m2[1]", 2)
-								expectVarExact(t, m2_1val, 0, "A", "10", noChildren)
-								expectVarExact(t, m2_1val, 1, "B", "11", noChildren)
+								m2kv1deref := client.ExpectVariablesResponse(t)
+								expectChildren(t, m2kv1deref, "*m2[1]", 2)
+								expectVarExact(t, m2kv1deref, 0, "A", "(*m2[1]).A", "10", noChildren)
+								expectVarExact(t, m2kv1deref, 1, "B", "(*m2[1]).B", "11", noChildren)
+								validateEvaluateName(t, client, m2kv1deref, 0)
+								validateEvaluateName(t, client, m2kv1deref, 1)
 							}
 						}
 					}
-					ref = expectVarExact(t, locals, -1, "m3", "<map[main.astruct]int> (length: 2)", hasChildren)
+					// key - compound, value - scalar
+					ref = expectVarExact(t, locals, -1, "m3", "m3", "<map[main.astruct]int> (length: 2)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m3 := client.ExpectVariablesResponse(t)
-						expectChildren(t, m3, "m3", 2)
-						ref = expectVarRegex(t, m3, 0, `<main\.astruct>\(0x[0-9a-f]+\)`, "42", hasChildren)
+						expectChildren(t, m3, "m3", 2) // each key-value represented by a single child
+						ref = expectVarRegex(t, m3, 0, `<main\.astruct>\(0x[0-9a-f]+\)`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
-							m3_0 := client.ExpectVariablesResponse(t)
-							expectChildren(t, m3_0, "m3[0]", 2)
-							expectVarExact(t, m3_0, 0, "A", "1", noChildren)
-							expectVarExact(t, m3_0, 1, "B", "1", noChildren)
+							m3kv0 := client.ExpectVariablesResponse(t)
+							expectChildren(t, m3kv0, "m3[0]", 2)
+							expectVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", noChildren)
+							validateEvaluateName(t, client, m3kv0, 0)
 						}
-						ref = expectVarRegex(t, m3, 1, `<main\.astruct>\(0x[0-9a-f]+\)`, "43", hasChildren)
-						if ref > 0 {
+						ref = expectVarRegex(t, m3, 1, `<main\.astruct>\(0x[0-9a-f]+\)`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", hasChildren)
+						if ref > 0 { // inspect another key from another key-value child
 							client.VariablesRequest(ref)
-							m3_1 := client.ExpectVariablesResponse(t)
-							expectChildren(t, m3_1, "m3[1]", 2)
-							expectVarExact(t, m3_1, 0, "A", "2", noChildren)
-							expectVarExact(t, m3_1, 1, "B", "2", noChildren)
+							m3kv1 := client.ExpectVariablesResponse(t)
+							expectChildren(t, m3kv1, "m3[1]", 2)
+							expectVarRegex(t, m3kv1, 1, "B", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", noChildren)
+							validateEvaluateName(t, client, m3kv1, 1)
 						}
 					}
-					ref = expectVarExact(t, locals, -1, "m4", "<map[main.astruct]main.astruct> (length: 2)", hasChildren)
+					// key - compound, value - compound
+					ref = expectVarExact(t, locals, -1, "m4", "m4", "<map[main.astruct]main.astruct> (length: 2)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m4 := client.ExpectVariablesResponse(t)
-						expectChildren(t, m4, "m4", 4)
-						expectVarExact(t, m4, 0, "[key 0]", "<main.astruct>", hasChildren)
-						expectVarExact(t, m4, 1, "[val 0]", "<main.astruct>", hasChildren)
-						ref = expectVarExact(t, m4, 2, "[key 1]", "<main.astruct>", hasChildren)
+						expectChildren(t, m4, "m4", 4) // each key and value represented by a child, so double the key-value count
+						expectVarRegex(t, m4, 0, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `<main\.astruct>`, hasChildren)
+						expectVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `<main\.astruct>`, hasChildren)
+						ref = expectVarRegex(t, m4, 2, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `<main\.astruct>`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m4Key1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m4Key1, "m4Key1", 2)
-							expectVarExact(t, m4Key1, 0, "A", "2", noChildren)
-							expectVarExact(t, m4Key1, 1, "B", "2", noChildren)
+							expectVarRegex(t, m4Key1, 0, "A", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "2", noChildren)
+							expectVarRegex(t, m4Key1, 1, "B", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", noChildren)
+							validateEvaluateName(t, client, m4Key1, 0)
+							validateEvaluateName(t, client, m4Key1, 1)
 						}
-						ref = expectVarExact(t, m4, 3, "[val 1]", "<main.astruct>", hasChildren)
+						ref = expectVarRegex(t, m4, 3, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `<main\.astruct>`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m4Val1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m4Val1, "m4Val1", 2)
-							expectVarExact(t, m4Val1, 0, "A", "22", noChildren)
-							expectVarExact(t, m4Val1, 1, "B", "22", noChildren)
+							expectVarRegex(t, m4Val1, 0, "A", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.A`, "22", noChildren)
+							expectVarRegex(t, m4Val1, 1, "B", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.B`, "22", noChildren)
+							validateEvaluateName(t, client, m4Val1, 0)
+							validateEvaluateName(t, client, m4Val1, 1)
 						}
 					}
-					expectVarExact(t, locals, -1, "emptymap", "<map[string]string> (length: 0)", noChildren)
+					expectVarExact(t, locals, -1, "emptymap", "emptymap", "<map[string]string> (length: 0)", noChildren)
 					// reflect.Kind == Ptr - see testvariables
 					// reflect.Kind == Slice
-					ref = expectVarExact(t, locals, -1, "zsslice", "<[]struct {}> (length: 3, cap: 3)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "zsslice", "zsslice", "<[]struct {}> (length: 3, cap: 3)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						zsslice := client.ExpectVariablesResponse(t)
 						expectChildren(t, zsslice, "zsslice", 3)
+						expectVarExact(t, zsslice, 2, "[2]", "zsslice[2]", "<struct {}>", noChildren)
+						validateEvaluateName(t, client, zsslice, 2)
 					}
-					expectVarExact(t, locals, -1, "emptyslice", "<[]string> (length: 0, cap: 0)", noChildren)
-					expectVarExact(t, locals, -1, "nilslice", "nil <[]int>", noChildren)
+					expectVarExact(t, locals, -1, "emptyslice", "emptyslice", "<[]string> (length: 0, cap: 0)", noChildren)
+					expectVarExact(t, locals, -1, "nilslice", "nilslice", "nil <[]int>", noChildren)
 					// reflect.Kind == String
-					expectVarExact(t, locals, -1, "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", noChildren)
+					expectVarExact(t, locals, -1, "longstr", "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", noChildren)
 					// reflect.Kind == Struct
-					expectVarExact(t, locals, -1, "zsvar", "<struct {}>", noChildren)
+					expectVarExact(t, locals, -1, "zsvar", "zsvar", "<struct {}>", noChildren)
 					// reflect.Kind == UnsafePointer
 					// TODO(polina): how do I test for unsafe.Pointer(nil)?
-					expectVarRegex(t, locals, -1, "upnil", `unsafe\.Pointer\(0x0\)`, noChildren)
-					expectVarRegex(t, locals, -1, "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, noChildren)
+					expectVarRegex(t, locals, -1, "upnil", "upnil", `unsafe\.Pointer\(0x0\)`, noChildren)
+					expectVarRegex(t, locals, -1, "up1", "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, noChildren)
 
 					// Test unreadable variable
-					ref = expectVarExact(t, locals, -1, "unread", "<*int>(0x3039)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "unread", "unread", "<*int>(0x3039)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						val := client.ExpectVariablesResponse(t)
 						expectChildren(t, val, "*unread", 1)
-						expectVarRegex(t, val, 0, "", "unreadable <.+>", noChildren)
+						expectVarRegex(t, val, 0, "^$", `\(\*unread\)`, "unreadable <.+>", noChildren)
+						validateEvaluateName(t, client, val, 0)
 					}
 
 					// Test that variables are not yet loaded completely.
-					ref = expectVarExact(t, locals, -1, "m1", "<map[string]main.astruct> (length: 66)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "m1", "m1", "<map[string]main.astruct> (length: 66)", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m1 := client.ExpectVariablesResponse(t)
@@ -1248,13 +1314,14 @@ func TestGlobalScopeAndVariables(t *testing.T) {
 					client.VariablesRequest(1002)
 					globals := client.ExpectVariablesResponse(t)
 					expectChildren(t, globals, "Globals", 1)
-					ref := expectVarExact(t, globals, 0, "SomeVar", "<github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType>", hasChildren)
+					ref := expectVarExact(t, globals, 0, "SomeVar", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar", "<github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType>", hasChildren)
 
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						somevar := client.ExpectVariablesResponse(t)
 						expectChildren(t, somevar, "SomeVar", 1)
-						expectVarExact(t, somevar, 0, "X", "0", noChildren)
+						// TODO(polina): unlike main.p, this prefix won't work
+						expectVarExact(t, somevar, 0, "X", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar.X", "0", noChildren)
 					}
 				},
 				disconnect: false,
@@ -1347,7 +1414,7 @@ func TestSetBreakpoint(t *testing.T) {
 					handleStop(t, client, 1, "main.loop", 8)
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
-					expectVarExact(t, locals, 0, "i", "0", noChildren) // i == 0
+					expectVarExact(t, locals, 0, "i", "i", "0", noChildren) // i == 0
 
 					// Edit the breakpoint to add a condition
 					client.SetConditionalBreakpointsRequest(fixture.Source, []int{8}, map[int]string{8: "i == 3"})
@@ -1360,7 +1427,7 @@ func TestSetBreakpoint(t *testing.T) {
 					handleStop(t, client, 1, "main.loop", 8)
 					client.VariablesRequest(1001) // Locals
 					locals = client.ExpectVariablesResponse(t)
-					expectVarExact(t, locals, 0, "i", "3", noChildren) // i == 3
+					expectVarExact(t, locals, 0, "i", "i", "3", noChildren) // i == 3
 
 					// Edit the breakpoint to remove a condition
 					client.SetConditionalBreakpointsRequest(fixture.Source, []int{8}, map[int]string{8: ""})
@@ -1373,7 +1440,7 @@ func TestSetBreakpoint(t *testing.T) {
 					handleStop(t, client, 1, "main.loop", 8)
 					client.VariablesRequest(1001) // Locals
 					locals = client.ExpectVariablesResponse(t)
-					expectVarExact(t, locals, 0, "i", "4", noChildren) // i == 4
+					expectVarExact(t, locals, 0, "i", "i", "4", noChildren) // i == 4
 
 					// Set at a line without a statement
 					client.SetBreakpointsRequest(fixture.Source, []int{1000})
@@ -1421,8 +1488,10 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						a5 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a5, "a5", 5)
-						expectVarExact(t, a5, 0, "[0]", "1", noChildren)
-						expectVarExact(t, a5, 4, "[4]", "5", noChildren)
+						expectVarExact(t, a5, 0, "[0]", "(a5)[0]", "1", noChildren)
+						expectVarExact(t, a5, 4, "[4]", "(a5)[4]", "5", noChildren)
+						validateEvaluateName(t, client, a5, 0)
+						validateEvaluateName(t, client, a5, 4)
 					}
 
 					// All (binary and unary) on basic types except <-, ++ and --
@@ -1449,7 +1518,7 @@ func TestEvaluateRequest(t *testing.T) {
 						expr := client.ExpectVariablesResponse(t)
 						expectChildren(t, expr, "(*int)(2)", 1)
 						// TODO(polina): should this be printed as (unknown int) instead?
-						expectVarExact(t, expr, 0, "", "<int>", noChildren)
+						expectVarExact(t, expr, 0, "", "(*((*int)(2)))", "<int>", noChildren)
 					}
 					// Type casts between string, []byte and []rune
 					client.EvaluateRequest("[]byte(\"ABC€\")", 1000, "this context will be ignored")
@@ -1476,7 +1545,8 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						expr := client.ExpectVariablesResponse(t)
 						expectChildren(t, expr, "mp[1]", 1)
-						expectVarExact(t, expr, 0, "data", "42", noChildren)
+						expectVarExact(t, expr, 0, "data", "(mp[1]).(data)", "42", noChildren)
+						validateEvaluateName(t, client, expr, 0)
 					}
 
 					// Pointer dereference
@@ -1487,7 +1557,8 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						expr := client.ExpectVariablesResponse(t)
 						expectChildren(t, expr, "*ms.Nest", 2)
-						expectVarExact(t, expr, 0, "Level", "1", noChildren)
+						expectVarExact(t, expr, 0, "Level", "(*ms.Nest).Level", "1", noChildren)
+						validateEvaluateName(t, client, expr, 0)
 					}
 
 					// Calls to builtin functions: cap, len, complex, imag and real
@@ -1622,7 +1693,7 @@ func TestEvaluateCallRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						rv := client.ExpectVariablesResponse(t)
 						expectChildren(t, rv, "rv", 1)
-						expectVarExact(t, rv, 0, "~r2", "3", noChildren)
+						expectVarExact(t, rv, 0, "~r2", "", "3", noChildren)
 					}
 					// One named return value
 					// Panic doesn't panic, but instead returns the error as a named return variable
@@ -1633,12 +1704,12 @@ func TestEvaluateCallRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						rv := client.ExpectVariablesResponse(t)
 						expectChildren(t, rv, "rv", 1)
-						ref = expectVarExact(t, rv, 0, "~panic", "<interface {}(string)>", hasChildren)
+						ref = expectVarExact(t, rv, 0, "~panic", "", "<interface {}(string)>", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							p := client.ExpectVariablesResponse(t)
 							expectChildren(t, p, "~panic", 1)
-							expectVarExact(t, p, 0, "data", "\"callpanic panicked\"", noChildren)
+							expectVarExact(t, p, 0, "data", "", "\"callpanic panicked\"", noChildren)
 						}
 					}
 					// Multiple return values
@@ -1649,8 +1720,8 @@ func TestEvaluateCallRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						rvs := client.ExpectVariablesResponse(t)
 						expectChildren(t, rvs, "rvs", 2)
-						expectVarExact(t, rvs, 0, "~r2", "1", noChildren)
-						expectVarExact(t, rvs, 1, "~r3", "2", noChildren)
+						expectVarExact(t, rvs, 0, "~r2", "", "1", noChildren)
+						expectVarExact(t, rvs, 1, "~r3", "", "2", noChildren)
 					}
 					// No frame defaults to top-most frame
 					client.EvaluateRequest("call call1(one, two)", 0, "this context will be ignored")
@@ -2027,6 +2098,9 @@ func TestAttachRequest(t *testing.T) {
 	if runtime.GOOS == "freebsd" {
 		t.SkipNow()
 	}
+	if runtime.GOOS == "windows" {
+		t.Skip("test skipped on windows, see https://delve.beta.teamcity.com/project/Delve_windows for details")
+	}
 	runTest(t, "loopprog", func(client *daptest.Client, fixture protest.Fixture) {
 		// Start the program to attach to
 		// TODO(polina): do I need to sanity check testBackend and runtime.GOOS?
@@ -2051,7 +2125,7 @@ func TestAttachRequest(t *testing.T) {
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
 					expectChildren(t, locals, "Locals", 1)
-					expectVarRegex(t, locals, 0, "i", "[0-9]+", noChildren)
+					expectVarRegex(t, locals, 0, "i", "i", "[0-9]+", noChildren)
 				},
 				disconnect: true,
 			}})
diff --git a/service/test/integration1_test.go b/service/test/integration1_test.go
index 08966c52..8b5afdab 100644
--- a/service/test/integration1_test.go
+++ b/service/test/integration1_test.go
@@ -730,19 +730,20 @@ func Test1ClientServer_FullStacktrace(t *testing.T) {
 		for _, g := range gs {
 			frames, err := c.Stacktrace(g.ID, 10, true)
 			assertNoError(err, t, fmt.Sprintf("Stacktrace(%d)", g.ID))
+			t.Logf("goroutine %d", g.ID)
 			for i, frame := range frames {
+				t.Logf("\tframe %d off=%#x bpoff=%#x pc=%#x %s:%d %s", i, frame.FrameOffset, frame.FramePointerOffset, frame.PC, frame.File, frame.Line, frame.Function.Name())
 				if frame.Function == nil {
 					continue
 				}
 				if frame.Function.Name() != "main.agoroutine" {
 					continue
 				}
-				t.Logf("frame %d: %v", i, frame)
 				for _, arg := range frame.Arguments {
 					if arg.Name != "i" {
 						continue
 					}
-					t.Logf("frame %d, variable i is %v\n", i, arg)
+					t.Logf("\tvariable i is %+v\n", arg)
 					argn, err := strconv.Atoi(arg.Value)
 					if err == nil {
 						found[argn] = true
@@ -757,6 +758,8 @@ func Test1ClientServer_FullStacktrace(t *testing.T) {
 			}
 		}
 
+		t.Logf("continue")
+
 		state = <-c.Continue()
 		if state.Err != nil {
 			t.Fatalf("Continue(): %v\n", state.Err)
@@ -767,10 +770,10 @@ func Test1ClientServer_FullStacktrace(t *testing.T) {
 
 		cur := 3
 		for i, frame := range frames {
+			t.Logf("\tframe %d off=%#x bpoff=%#x pc=%#x %s:%d %s", i, frame.FrameOffset, frame.FramePointerOffset, frame.PC, frame.File, frame.Line, frame.Function.Name())
 			if i == 0 {
 				continue
 			}
-			t.Logf("frame %d: %v", i, frame)
 			v := frame.Var("n")
 			if v == nil {
 				t.Fatalf("Could not find value of variable n in frame %d", i)
diff --git a/service/test/integration2_test.go b/service/test/integration2_test.go
index 06527e14..e0468a6b 100644
--- a/service/test/integration2_test.go
+++ b/service/test/integration2_test.go
@@ -925,19 +925,20 @@ func TestClientServer_FullStacktrace(t *testing.T) {
 		for _, g := range gs {
 			frames, err := c.Stacktrace(g.ID, 10, 0, &normalLoadConfig)
 			assertNoError(err, t, fmt.Sprintf("Stacktrace(%d)", g.ID))
+			t.Logf("goroutine %d", g.ID)
 			for i, frame := range frames {
+				t.Logf("\tframe %d off=%#x bpoff=%#x pc=%#x %s:%d %s", i, frame.FrameOffset, frame.FramePointerOffset, frame.PC, frame.File, frame.Line, frame.Function.Name())
 				if frame.Function == nil {
 					continue
 				}
 				if frame.Function.Name() != "main.agoroutine" {
 					continue
 				}
-				t.Logf("frame %d: %v", i, frame)
 				for _, arg := range frame.Arguments {
 					if arg.Name != "i" {
 						continue
 					}
-					t.Logf("frame %v, variable i is %v\n", frame, arg)
+					t.Logf("\tvariable i is %+v\n", arg)
 					argn, err := strconv.Atoi(arg.Value)
 					if err == nil {
 						found[argn] = true
@@ -952,6 +953,8 @@ func TestClientServer_FullStacktrace(t *testing.T) {
 			}
 		}
 
+		t.Logf("continue")
+
 		state = <-c.Continue()
 		if state.Err != nil {
 			t.Fatalf("Continue(): %v\n", state.Err)
@@ -962,10 +965,10 @@ func TestClientServer_FullStacktrace(t *testing.T) {
 
 		cur := 3
 		for i, frame := range frames {
+			t.Logf("\tframe %d off=%#x bpoff=%#x pc=%#x %s:%d %s", i, frame.FrameOffset, frame.FramePointerOffset, frame.PC, frame.File, frame.Line, frame.Function.Name())
 			if i == 0 {
 				continue
 			}
-			t.Logf("frame %d: %v", i, frame)
 			v := frame.Var("n")
 			if v == nil {
 				t.Fatalf("Could not find value of variable n in frame %d", i)