From e5006c105c44a863f4bbb4bf9a8ca8a530d996b9 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Tue, 6 Dec 2022 00:21:52 +0100 Subject: [PATCH] Test windows/arm64 pipeline (#3200) * Test windows/arm64 pipeline * update build script to support windows/arm64 * skip TestLaunchRequestWithRelativeExecPath is symblink can't be created * partially fix and skip TestCgoStacktrace * update backend health docs * update * log test output * skip starbind test on windows arm64 * skip starbind test on windows arm64 * skip rtype test on windows arm64 * skip pie backend tests on windows/arm64 * fix tests * skip function calls test on windows/arm64 * fix tests * revert hardware breakpoint test relax * add pie test clarification * skip symlink test only on windows * skip TestStepConcurrentDirect * readd exp.winarm64 * fix param * add exp.winarm64 tags * skip TestGeneratedDoc on winarm64 --- .teamcity/settings.kts | 2 +- Documentation/backend_test_health.md | 3 + _fixtures/cgostacktest/hello.c | 4 ++ _scripts/make.go | 46 ++++++++------- _scripts/test_windows.ps1 | 84 ++++++++++++++++------------ cmd/dlv/dlv_test.go | 12 +++- pkg/proc/proc_test.go | 13 ++++- pkg/proc/target.go | 2 +- pkg/proc/test/support.go | 2 +- service/dap/server_test.go | 8 ++- 10 files changed, 110 insertions(+), 66 deletions(-) diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts index d0f060dc4d..b8c62b5ab0 100644 --- a/.teamcity/settings.kts +++ b/.teamcity/settings.kts @@ -204,7 +204,7 @@ class TestBuild(val os: String, val arch: String, version: String, buildId: Abso scriptMode = file { path = "_scripts/test_windows.ps1" } - param("jetbrains_powershell_scriptArguments", "-version ${"go$version"} -arch $arch") + param("jetbrains_powershell_scriptArguments", "-version ${"go$version"} -arch $arch -binDir %teamcity.build.systemDir%") } } "mac" -> { diff --git a/Documentation/backend_test_health.md b/Documentation/backend_test_health.md index eff970fe29..6ee41512ea 100644 --- a/Documentation/backend_test_health.md +++ b/Documentation/backend_test_health.md @@ -22,3 +22,6 @@ Tests skipped by each supported backend: * 1 broken * 3 see https://github.com/go-delve/delve/issues/2768 * 1 upstream issue +* windows/arm64 skipped = 2 + * 1 broken - cgo stacktraces + * 1 broken - step concurrent diff --git a/_fixtures/cgostacktest/hello.c b/_fixtures/cgostacktest/hello.c index 7226ffed8c..edcef6b7e4 100644 --- a/_fixtures/cgostacktest/hello.c +++ b/_fixtures/cgostacktest/hello.c @@ -7,8 +7,12 @@ #elif __i386__ #define BREAKPOINT asm("int3;") #elif __aarch64__ +#ifdef WIN32 +#define BREAKPOINT asm("brk 0xF000;") +#else #define BREAKPOINT asm("brk 0;") #endif +#endif void helloworld_pt2(int x) { BREAKPOINT; diff --git a/_scripts/make.go b/_scripts/make.go index 0f4a96981a..dd0e7a4295 100644 --- a/_scripts/make.go +++ b/_scripts/make.go @@ -42,15 +42,6 @@ func NewMakeCommands() *cobra.Command { Use: "build", Short: "Build delve", Run: func(cmd *cobra.Command, args []string) { - tagFlag := prepareMacnative() - if len(*Tags) > 0 { - if len(tagFlag) == 0 { - tagFlag = "-tags=" - } else { - tagFlag += "," - } - tagFlag += strings.Join(*Tags, ",") - } envflags := []string{} if len(Architecture) > 0 { envflags = append(envflags, "GOARCH="+Architecture) @@ -59,9 +50,9 @@ func NewMakeCommands() *cobra.Command { envflags = append(envflags, "GOOS="+OS) } if len(envflags) > 0 { - executeEnv(envflags, "go", "build", "-ldflags", "-extldflags -static", tagFlag, buildFlags(), DelveMainPackagePath) + executeEnv(envflags, "go", "build", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath) } else { - execute("go", "build", "-ldflags", "-extldflags -static", tagFlag, buildFlags(), DelveMainPackagePath) + execute("go", "build", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath) } if runtime.GOOS == "darwin" && os.Getenv("CERT") != "" && canMacnative() { codesign("./dlv") @@ -78,8 +69,7 @@ func NewMakeCommands() *cobra.Command { Use: "install", Short: "Installs delve", Run: func(cmd *cobra.Command, args []string) { - tagFlag := prepareMacnative() - execute("go", "install", tagFlag, buildFlags(), DelveMainPackagePath) + execute("go", "install", tagFlags(), buildFlags(), DelveMainPackagePath) if runtime.GOOS == "darwin" && os.Getenv("CERT") != "" && canMacnative() { codesign(installedExecutablePath()) } @@ -290,7 +280,24 @@ func prepareMacnative() string { if !checkCert() { return "" } - return "-tags=macnative" + return "macnative" +} + +func tagFlags() string { + var tags []string + if mactags := prepareMacnative(); mactags != "" { + tags = append(tags, mactags) + } + if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" { + tags = append(tags, "exp.winarm64") + } + if Tags != nil && len(*Tags) > 0 { + tags = append(tags, *Tags...) + } + if len(tags) == 0 { + return "" + } + return "-tags=" + strings.Join(tags, ",") } func buildFlags() []string { @@ -390,8 +397,9 @@ func testStandard() { case "linux": dopie = true case "windows": + // windows/arm64 always uses pie buildmode, no need to test everything again. // only on Go 1.15 or later, with CGO_ENABLED and gcc found in path - if goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) { + if runtime.GOARCH != "arm64" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) { out, err := exec.Command("go", "env", "CGO_ENABLED").CombinedOutput() if err != nil { panic(err) @@ -451,11 +459,11 @@ func testCmdIntl(testSet, testRegex, testBackend, testBuildMode string) { } if len(testPackages) > 3 { - executeq(env, "go", "test", testFlags(), buildFlags(), testPackages, backendFlag, buildModeFlag) + executeq(env, "go", "test", testFlags(), buildFlags(), tagFlags(), testPackages, backendFlag, buildModeFlag) } else if testRegex != "" { - executeq(env, "go", "test", testFlags(), buildFlags(), testPackages, "-run="+testRegex, backendFlag, buildModeFlag) + executeq(env, "go", "test", testFlags(), buildFlags(), tagFlags(), testPackages, "-run="+testRegex, backendFlag, buildModeFlag) } else { - executeq(env, "go", "test", testFlags(), buildFlags(), testPackages, backendFlag, buildModeFlag) + executeq(env, "go", "test", testFlags(), buildFlags(), tagFlags(), testPackages, backendFlag, buildModeFlag) } } @@ -494,7 +502,7 @@ func inpath(exe string) bool { func allPackages() []string { r := []string{} - for _, dir := range strings.Split(getoutput("go", "list", "-mod=vendor", "./..."), "\n") { + for _, dir := range strings.Split(getoutput("go", "list", "-mod=vendor", tagFlags(), "./..."), "\n") { dir = strings.TrimSpace(dir) if dir == "" || strings.Contains(dir, "/vendor/") || strings.Contains(dir, "/_scripts") { continue diff --git a/_scripts/test_windows.ps1 b/_scripts/test_windows.ps1 index e5c5db09bc..ff5422daeb 100644 --- a/_scripts/test_windows.ps1 +++ b/_scripts/test_windows.ps1 @@ -1,55 +1,73 @@ param ( [Parameter(Mandatory = $true)][string]$version, - [Parameter(Mandatory = $true)][string]$arch + [Parameter(Mandatory = $true)][string]$arch, + [Parameter(Mandatory = $false)][string]$binDir ) -Set-MpPreference -DisableRealtimeMonitoring $true - -if ($arch -eq "arm64") { - # TODO: Remove when TeamCity subproject for windows/arm64 is set up. - Exit 0 +if ($binDir -eq "") { + # TODO: remove once the current version of settings.kts gets to master. + $binDir = Resolve-Path "../../system" # working directory } -# Install Chocolatey -#Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + +Set-MpPreference -DisableRealtimeMonitoring $true -ErrorAction SilentlyContinue # Install MinGW. -choco install -y mingw +if ($arch -eq "amd64") +{ + # Install Chocolatey + #Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + choco install -y mingw +} elseif ($arch -eq "arm64") { + $llvmVersion = "20220906" + $name = "llvm-mingw-$llvmVersion-ucrt-aarch64" + if (-Not(Test-Path "$binDir\llvm-mingw\$name")) + { + New-Item "$binDir\llvm-mingw" -ItemType Directory -ErrorAction SilentlyContinue + $url = "https://github.com/mstorsjo/llvm-mingw/releases/download/$llvmVersion/$name.zip" + Invoke-WebRequest -UserAgent wget -Uri $url -OutFile "$env:TEMP\$name.zip" + Expand-Archive -Force -LiteralPath "$env:TEMP\$name.zip" -DestinationPath "$binDir\llvm-mingw\" + } + $env:PATH = "$binDir\llvm-mingw\$name\bin;$env:PATH" +} else { + Write-Error "Unsupported architecture: $arch" -ErrorAction Stop +} # Install Procdump -if (-Not(Test-Path "C:\procdump")) +if (-Not(Test-Path "$binDir\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 + New-Item "$binDir\procdump" -ItemType Directory + Invoke-WebRequest -UserAgent wget -Uri "https://download.sysinternals.com/files/Procdump.zip" -OutFile "$env:TEMP\procdump.zip" + Expand-Archive -Force -LiteralPath "$env:TEMP\procdump.zip" -DestinationPath "$binDir\procdump" } -$env:PATH += ";C:\procdump;C:\mingw64\bin" +$env:PATH = "$binDir\procdump;$env:PATH" function GetGo($version) { - $env:GOROOT = "C:\go\$version" + $env:GOROOT = "$binDir\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 + Invoke-WebRequest -UserAgent wget -Uri $url -OutFile "$env:TEMP\$file" + Expand-Archive -Force -LiteralPath "$env:TEMP\$file" -DestinationPath "$env:TEMP\$version" + New-Item $env:GOROOT -ItemType Directory + Move-Item -Path "$env:TEMP\$version\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 + $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" + $env:GOROOT = "$binDir\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 + git clone "https://go.googlesource.com/go" "$binDir\go\go-tip" + Push-Location -Path "$binDir\go\go-tip\src" } else { - Push-Location -Path C:\go\go-tip\src + Push-Location -Path "$binDir\go\go-tip\src" git pull } .\make.bat @@ -57,7 +75,7 @@ if ($version -eq "gotip") { } else { # Install Go Write-Host "Finding latest patch version for $version" - $versions = Invoke-WebRequest -Uri 'https://golang.org/dl/?mode=json&include=all' -UseBasicParsing | foreach {$_.Content} | ConvertFrom-Json + $versions = Invoke-WebRequest -Uri "https://golang.org/dl/?mode=json&include=all" -UseBasicParsing | foreach {$_.Content} | ConvertFrom-Json $v = $versions | foreach {$_.version} | Select-String -Pattern "^$version($|\.)" | Sort-Object -Descending | Select-Object -First 1 if ($v -eq $null) { $v = $versions | foreach {$_.version} | Select-String -Pattern "^$version(rc)" | Sort-Object -Descending | Select-Object -First 1 @@ -69,25 +87,17 @@ if ($version -eq "gotip") { GetGo $v } -$env:GOPATH = "C:\gopath" -$env:PATH += ";$env:GOROOT\bin;$env:GOPATH\bin" +$env:GOPATH = "$binDir\gopath" +$env:PATH = "$env:GOROOT\bin;$env:GOPATH\bin;$env:PATH" Write-Host $env:PATH Write-Host $env:GOROOT Write-Host $env:GOPATH +Get-Command go go version go env -go run _scripts/make.go test -$x = $LastExitCode -if ($version -ne "gotip") { - Exit $x -} - -# TODO: Remove once we have a windows/arm64 builder. -# Test windows/arm64 compiles. -$env:GOARCH = "arm64" -go run _scripts/make.go build --tags exp.winarm64 +go run _scripts/make.go test -v $x = $LastExitCode if ($version -ne "gotip") { - Exit $x + Exit $x } diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go index a7ed67dd14..cfec1439fd 100644 --- a/cmd/dlv/dlv_test.go +++ b/cmd/dlv/dlv_test.go @@ -210,7 +210,11 @@ func getDlvBin(t *testing.T) (string, string) { // we can ensure we don't get build errors // depending on the test ordering. os.Setenv("CGO_LDFLAGS", ldFlags) - return getDlvBinInternal(t) + var tags string + if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" { + tags = "-tags=exp.winarm64" + } + return getDlvBinInternal(t, tags) } func getDlvBinEBPF(t *testing.T) (string, string) { @@ -424,6 +428,10 @@ func TestGeneratedDoc(t *testing.T) { if strings.ToLower(os.Getenv("TRAVIS")) == "true" && runtime.GOOS == "windows" { t.Skip("skipping test on Windows in CI") } + if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" { + //TODO(qmuntal): investigate further when the Windows ARM64 backend is more stable. + t.Skip("skipping test on Windows in CI") + } // Checks gen-cli-docs.go var generatedBuf bytes.Buffer commands := terminal.DebugCommands(nil) @@ -457,9 +465,9 @@ func TestGeneratedDoc(t *testing.T) { return out } + checkAutogenDoc(t, "Documentation/backend_test_health.md", "go run _scripts/gen-backend_test_health.go", runScript("_scripts/gen-backend_test_health.go", "-")) checkAutogenDoc(t, "pkg/terminal/starbind/starlark_mapping.go", "'go generate' inside pkg/terminal/starbind", runScript("_scripts/gen-starlark-bindings.go", "go", "-")) checkAutogenDoc(t, "Documentation/cli/starlark.md", "'go generate' inside pkg/terminal/starbind", runScript("_scripts/gen-starlark-bindings.go", "doc/dummy", "Documentation/cli/starlark.md")) - checkAutogenDoc(t, "Documentation/backend_test_health.md", "go run _scripts/gen-backend_test_health.go", runScript("_scripts/gen-backend_test_health.go", "-")) if goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { checkAutogenDoc(t, "_scripts/rtype-out.txt", "go run _scripts/rtype.go report _scripts/rtype-out.txt", runScript("_scripts/rtype.go", "report")) runScript("_scripts/rtype.go", "check") diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index e77c54dbbc..02d8d83328 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -2482,6 +2482,7 @@ func TestStepOut(t *testing.T) { func TestStepConcurrentDirect(t *testing.T) { skipOn(t, "broken", "freebsd") + skipOn(t, "broken - step concurrent", "windows", "arm64") protest.AllowRecording(t) withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { bp := setFileBreakpoint(p, t, fixture.Source, 37) @@ -3424,6 +3425,7 @@ func TestCgoStacktrace(t *testing.T) { } skipOn(t, "broken - cgo stacktraces", "386") + skipOn(t, "broken - cgo stacktraces", "windows", "arm64") protest.MustHaveCgo(t) // Tests that: @@ -3635,8 +3637,8 @@ func TestIssue1008(t *testing.T) { if !strings.HasSuffix(loc.File, "/main.go") { t.Errorf("unexpected location %s:%d\n", loc.File, loc.Line) } - if loc.Line > 31 { - t.Errorf("unexpected location %s:%d (file only has 30 lines)\n", loc.File, loc.Line) + if loc.Line > 35 { + t.Errorf("unexpected location %s:%d (file only has 34 lines)\n", loc.File, loc.Line) } }) } @@ -4042,10 +4044,15 @@ func TestInlineStepOut(t *testing.T) { func TestInlineFunctionList(t *testing.T) { // We should be able to list all functions, even inlined ones. - if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { + ver, _ := goversion.Parse(runtime.Version()) + if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { // Versions of go before 1.10 do not have DWARF information for inlined calls t.Skip("inlining not supported") } + if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" { + // TODO(qmuntal): seems to be an upstream issue, investigate. + t.Skip("inlining not supported") + } withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) { var found bool for _, fn := range p.BinInfo().Functions { diff --git a/pkg/proc/target.go b/pkg/proc/target.go index f556fee834..35d4c23f48 100644 --- a/pkg/proc/target.go +++ b/pkg/proc/target.go @@ -268,7 +268,7 @@ func (t *Target) Valid() (bool, error) { // Currently only non-recorded processes running on AMD64 support // function calls. func (t *Target) SupportsFunctionCalls() bool { - return t.Process.BinInfo().Arch.Name == "amd64" || t.Process.BinInfo().Arch.Name == "arm64" + return t.Process.BinInfo().Arch.Name == "amd64" || (t.Process.BinInfo().Arch.Name == "arm64" && t.Process.BinInfo().GOOS != "windows") } // ClearCaches clears internal caches that should not survive a restart. diff --git a/pkg/proc/test/support.go b/pkg/proc/test/support.go index bd5086738f..a9261e1ada 100644 --- a/pkg/proc/test/support.go +++ b/pkg/proc/test/support.go @@ -341,7 +341,7 @@ func MustSupportFunctionCalls(t *testing.T, testBackend string) { t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH)) } if runtime.GOARCH == "arm64" { - if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 19) { + if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 19) || runtime.GOOS == "windows" { t.Skip("this version of Go does not support function calls") } } diff --git a/service/dap/server_test.go b/service/dap/server_test.go index 5615d42822..159392855d 100644 --- a/service/dap/server_test.go +++ b/service/dap/server_test.go @@ -5472,10 +5472,14 @@ func TestLaunchRequestWithRelativeExecPath(t *testing.T) { runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { symlink := "./__thisexe" err := os.Symlink(fixture.Path, symlink) - defer os.Remove(symlink) if err != nil { - t.Fatal("unable to create relative symlink:", err) + if runtime.GOOS == "windows" { + t.Skip("this test requires symlinks to be enabled and allowed") + } else { + t.Fatal("unable to create relative symlink:", err) + } } + defer os.Remove(symlink) runDebugSession(t, client, "launch", func() { client.LaunchRequestWithArgs(map[string]interface{}{ "mode": "exec", "program": symlink})