diff --git a/g3doc/user_guide/debugging.md b/g3doc/user_guide/debugging.md index 2291b5fab..edf1d4025 100644 --- a/g3doc/user_guide/debugging.md +++ b/g3doc/user_guide/debugging.md @@ -65,7 +65,7 @@ Install a runsc with debug symbols (you can also use the [nightly release](../install/#nightly)): ```bash -make dev BAZEL_OPTIONS="-c dbg" +make dev BAZEL_OPTIONS="-c dbg --define gotags=debug" ``` Start the container you want to debug using the runsc runtime with debug @@ -94,6 +94,32 @@ In a different window connect to nginx to trigger the breakpoint: curl http://localhost:8080/ ``` +It's also easy to attach a debugger to one of the predefined syscall tests when +you're working on specific gVisor features. With the `delay-for-debugger` flag +you can pause the test runner before execution so that you can attach the +sandbox process to a debugger. Here is an example: + +```bash + make test BAZEL_OPTIONS="-c dbg --define gotags=debug" \ + OPTIONS="--test_arg=--delay-for-debugger=5m --test_output=streamed" \ + TARGETS=//test/syscalls:mount_test_runsc_systrap +``` + +The `delay-for-debugger=5m` flag means the test runner will pause for 5 minutes +before running the test. To attach to the sandbox process, you can run the +following in a separate window. + +```bash +dlv attach $(ps aux | grep -m 1 -e 'runsc-sandbox' | awk '{print $2}') +``` + +Once you've attached to the process and set a breakpoint, you can signal the +test to start by running the following in another separate window. + +```bash +kill -SIGUSR1 $(ps aux | grep -m 1 -e 'bash.*test/syscalls' | awk '{print $2}') +``` + ## Profiling `runsc` integrates with Go profiling tools and gives you easy commands to diff --git a/runsc/boot/platforms/BUILD b/runsc/boot/platforms/BUILD index 34236738c..ec34889e0 100644 --- a/runsc/boot/platforms/BUILD +++ b/runsc/boot/platforms/BUILD @@ -13,6 +13,7 @@ exempt_go_library( srcs = [ "platforms.go", "platforms_darwin.go", + "platforms_debug.go", ], # Nothing needs to be stateified, and stateify has trouble when select is # used to choose deps. diff --git a/runsc/boot/platforms/platforms.go b/runsc/boot/platforms/platforms.go index eebd96b87..5e3f16155 100644 --- a/runsc/boot/platforms/platforms.go +++ b/runsc/boot/platforms/platforms.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build linux -// +build linux +//go:build linux && !debug +// +build linux,!debug // Package platforms imports all available platform packages. package platforms diff --git a/runsc/boot/platforms/platforms_debug.go b/runsc/boot/platforms/platforms_debug.go new file mode 100644 index 000000000..e23e69422 --- /dev/null +++ b/runsc/boot/platforms/platforms_debug.go @@ -0,0 +1,28 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build linux && debug +// +build linux,debug + +package platforms + +import ( + // Import platforms that runsc might use. + + // The KVM platform is not included because it's incompatible with debug + // builds. Unoptimized functions grow the stack too much and fail the nosplit + // check. + _ "gvisor.dev/gvisor/pkg/sentry/platform/ptrace" + _ "gvisor.dev/gvisor/pkg/sentry/platform/systrap" +) diff --git a/test/runner/main.go b/test/runner/main.go index 573fe4e46..7059a1227 100644 --- a/test/runner/main.go +++ b/test/runner/main.go @@ -332,10 +332,17 @@ func runRunsc(tc *gtest.TestCase, spec *specs.Spec) error { if err != nil { return fmt.Errorf("could not read pid file: %v", err) } - log.Infof("Sandbox process ID is %s. You can attach to it from a debugger of your choice.", sandboxPidBytes) - log.Infof("For example, with Delve you can call: $ dlv attach %s", sandboxPidBytes) - log.Infof("The test will automatically start after %s.", *waitForPid) - log.Infof("You may also signal the test process to start the test immediately: $ kill -SIGUSR1 %d", os.Getpid()) + msg := ` + + Sandbox is running. You can now attach to it from a debugger of your choice. + For example, with Delve you can call: $ dlv attach %s. + The test will automatically start after %s. + You may also signal the test process to start the test immediately: $ kill -SIGUSR1 %d. + + If you're running a test using Make/docker, you'll have to obtain the runsc and test PIDs manually. + To attach run: $ dlv attach $(ps aux | grep -m 1 -e 'runsc-sandbox' | awk '{print $2}') + To signal the test process run: $ kill -SIGUSR1 $(ps aux | grep -m 1 -e 'bash.*test/syscalls' | awk '{print $2}')` + log.Infof(msg, sandboxPidBytes, *waitForPid, os.Getpid()) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, unix.SIGUSR1) diff --git a/tools/bazeldefs/go.bzl b/tools/bazeldefs/go.bzl index 2122f372d..57d6c8c48 100644 --- a/tools/bazeldefs/go.bzl +++ b/tools/bazeldefs/go.bzl @@ -57,7 +57,11 @@ def go_binary(name, static = False, pure = False, x_defs = None, **kwargs): kwargs["pure"] = "on" gc_goopts = select({ "//conditions:default": kwargs.pop("gc_goopts", []), - "//tools:debug": kwargs.pop("gc_goopts", []) + ["-all=-N -l"], + "//tools:debug": kwargs.pop("gc_goopts", []) + ["-N", "-l"], + }) + kwargs["gotags"] = select({ + "//conditions:default": kwargs.pop("gotags", []), + "//tools:debug": kwargs.pop("gotags", []) + ["debug"], }) _go_binary( name = name,