diff options
Diffstat (limited to 'runsc/cmd')
-rw-r--r-- | runsc/cmd/BUILD | 2 | ||||
-rw-r--r-- | runsc/cmd/boot.go | 6 | ||||
-rw-r--r-- | runsc/cmd/checkpoint.go | 5 | ||||
-rw-r--r-- | runsc/cmd/debug.go | 4 | ||||
-rw-r--r-- | runsc/cmd/delete.go | 2 | ||||
-rw-r--r-- | runsc/cmd/do.go | 2 | ||||
-rw-r--r-- | runsc/cmd/events.go | 11 | ||||
-rw-r--r-- | runsc/cmd/exec.go | 4 | ||||
-rw-r--r-- | runsc/cmd/kill.go | 2 | ||||
-rw-r--r-- | runsc/cmd/list.go | 2 | ||||
-rw-r--r-- | runsc/cmd/pause.go | 2 | ||||
-rw-r--r-- | runsc/cmd/ps.go | 2 | ||||
-rw-r--r-- | runsc/cmd/resume.go | 2 | ||||
-rw-r--r-- | runsc/cmd/start.go | 9 | ||||
-rw-r--r-- | runsc/cmd/state.go | 2 | ||||
-rw-r--r-- | runsc/cmd/symbolize.go | 91 | ||||
-rw-r--r-- | runsc/cmd/wait.go | 2 |
17 files changed, 128 insertions, 22 deletions
diff --git a/runsc/cmd/BUILD b/runsc/cmd/BUILD index 2556f6d9e..19520d7ab 100644 --- a/runsc/cmd/BUILD +++ b/runsc/cmd/BUILD @@ -32,6 +32,7 @@ go_library( "start.go", "state.go", "statefile.go", + "symbolize.go", "syscalls.go", "wait.go", ], @@ -39,6 +40,7 @@ go_library( "//runsc:__subpackages__", ], deps = [ + "//pkg/coverage", "//pkg/log", "//pkg/p9", "//pkg/sentry/control", diff --git a/runsc/cmd/boot.go b/runsc/cmd/boot.go index cd419e1aa..2c92e3067 100644 --- a/runsc/cmd/boot.go +++ b/runsc/cmd/boot.go @@ -131,11 +131,11 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) return subcommands.ExitUsageError } - // Ensure that if there is a panic, all goroutine stacks are printed. - debug.SetTraceback("system") - conf := args[0].(*config.Config) + // Set traceback level + debug.SetTraceback(conf.Traceback) + if b.attached { // Ensure this process is killed after parent process terminates when // attached mode is enabled. In the unfortunate event that the parent diff --git a/runsc/cmd/checkpoint.go b/runsc/cmd/checkpoint.go index 8fe0c427a..c0bc8f064 100644 --- a/runsc/cmd/checkpoint.go +++ b/runsc/cmd/checkpoint.go @@ -75,7 +75,7 @@ func (c *Checkpoint) Execute(_ context.Context, f *flag.FlagSet, args ...interfa conf := args[0].(*config.Config) waitStatus := args[1].(*syscall.WaitStatus) - cont, err := container.Load(conf.RootDir, id) + cont, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } @@ -149,6 +149,9 @@ func (c *Checkpoint) Execute(_ context.Context, f *flag.FlagSet, args ...interfa } ws, err := cont.Wait() + if err != nil { + Fatalf("Error waiting for container: %v", err) + } *waitStatus = ws return subcommands.ExitSuccess diff --git a/runsc/cmd/debug.go b/runsc/cmd/debug.go index 132198222..609e8231c 100644 --- a/runsc/cmd/debug.go +++ b/runsc/cmd/debug.go @@ -91,7 +91,7 @@ func (d *Debug) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) return subcommands.ExitUsageError } var err error - c, err = container.Load(conf.RootDir, f.Arg(0)) + c, err = container.LoadAndCheck(conf.RootDir, f.Arg(0)) if err != nil { return Errorf("loading container %q: %v", f.Arg(0), err) } @@ -106,7 +106,7 @@ func (d *Debug) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) return Errorf("listing containers: %v", err) } for _, id := range ids { - candidate, err := container.Load(conf.RootDir, id) + candidate, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { return Errorf("loading container %q: %v", id, err) } diff --git a/runsc/cmd/delete.go b/runsc/cmd/delete.go index 4e49deff8..a25637265 100644 --- a/runsc/cmd/delete.go +++ b/runsc/cmd/delete.go @@ -68,7 +68,7 @@ func (d *Delete) Execute(_ context.Context, f *flag.FlagSet, args ...interface{} func (d *Delete) execute(ids []string, conf *config.Config) error { for _, id := range ids { - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { if os.IsNotExist(err) && d.force { log.Warningf("couldn't find container %q: %v", id, err) diff --git a/runsc/cmd/do.go b/runsc/cmd/do.go index 640de4c47..8a8d9f752 100644 --- a/runsc/cmd/do.go +++ b/runsc/cmd/do.go @@ -81,7 +81,7 @@ func (c *Do) SetFlags(f *flag.FlagSet) { // Execute implements subcommands.Command.Execute. func (c *Do) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { if len(f.Args()) == 0 { - c.Usage() + f.Usage() return subcommands.ExitUsageError } diff --git a/runsc/cmd/events.go b/runsc/cmd/events.go index 25fe2cf1c..3836b7b4e 100644 --- a/runsc/cmd/events.go +++ b/runsc/cmd/events.go @@ -74,7 +74,7 @@ func (evs *Events) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa id := f.Arg(0) conf := args[0].(*config.Config) - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading sandbox: %v", err) } @@ -85,7 +85,12 @@ func (evs *Events) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa ev, err := c.Event() if err != nil { log.Warningf("Error getting events for container: %v", err) + if evs.stats { + return subcommands.ExitFailure + } } + log.Debugf("Events: %+v", ev) + // err must be preserved because it is used below when breaking // out of the loop. b, err := json.Marshal(ev) @@ -101,11 +106,9 @@ func (evs *Events) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa if err != nil { return subcommands.ExitFailure } - break + return subcommands.ExitSuccess } time.Sleep(time.Duration(evs.intervalSec) * time.Second) } - - return subcommands.ExitSuccess } diff --git a/runsc/cmd/exec.go b/runsc/cmd/exec.go index 775ed4b43..eafd6285c 100644 --- a/runsc/cmd/exec.go +++ b/runsc/cmd/exec.go @@ -112,7 +112,7 @@ func (ex *Exec) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) } waitStatus := args[1].(*syscall.WaitStatus) - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading sandbox: %v", err) } @@ -150,7 +150,7 @@ func (ex *Exec) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) } func (ex *Exec) exec(c *container.Container, e *control.ExecArgs, waitStatus *syscall.WaitStatus) subcommands.ExitStatus { - // Start the new process and get it pid. + // Start the new process and get its pid. pid, err := c.Execute(e) if err != nil { return Errorf("executing processes for container: %v", err) diff --git a/runsc/cmd/kill.go b/runsc/cmd/kill.go index 04eee99b2..fe69e2a08 100644 --- a/runsc/cmd/kill.go +++ b/runsc/cmd/kill.go @@ -69,7 +69,7 @@ func (k *Kill) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) Fatalf("it is invalid to specify both --all and --pid") } - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } diff --git a/runsc/cmd/list.go b/runsc/cmd/list.go index f92d6fef9..6907eb16a 100644 --- a/runsc/cmd/list.go +++ b/runsc/cmd/list.go @@ -79,7 +79,7 @@ func (l *List) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) // Collect the containers. var containers []*container.Container for _, id := range ids { - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container %q: %v", id, err) } diff --git a/runsc/cmd/pause.go b/runsc/cmd/pause.go index 0eb1402ed..fe7d4e257 100644 --- a/runsc/cmd/pause.go +++ b/runsc/cmd/pause.go @@ -55,7 +55,7 @@ func (*Pause) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) s id := f.Arg(0) conf := args[0].(*config.Config) - cont, err := container.Load(conf.RootDir, id) + cont, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } diff --git a/runsc/cmd/ps.go b/runsc/cmd/ps.go index bc58c928f..18d7a1436 100644 --- a/runsc/cmd/ps.go +++ b/runsc/cmd/ps.go @@ -60,7 +60,7 @@ func (ps *PS) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) id := f.Arg(0) conf := args[0].(*config.Config) - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading sandbox: %v", err) } diff --git a/runsc/cmd/resume.go b/runsc/cmd/resume.go index f24823f99..a00928204 100644 --- a/runsc/cmd/resume.go +++ b/runsc/cmd/resume.go @@ -56,7 +56,7 @@ func (r *Resume) Execute(_ context.Context, f *flag.FlagSet, args ...interface{} id := f.Arg(0) conf := args[0].(*config.Config) - cont, err := container.Load(conf.RootDir, id) + cont, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } diff --git a/runsc/cmd/start.go b/runsc/cmd/start.go index 88991b521..f6499cc44 100644 --- a/runsc/cmd/start.go +++ b/runsc/cmd/start.go @@ -21,6 +21,7 @@ import ( "gvisor.dev/gvisor/runsc/config" "gvisor.dev/gvisor/runsc/container" "gvisor.dev/gvisor/runsc/flag" + "gvisor.dev/gvisor/runsc/specutils" ) // Start implements subcommands.Command for the "start" command. @@ -54,10 +55,16 @@ func (*Start) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) s id := f.Arg(0) conf := args[0].(*config.Config) - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } + // Read the spec again here to ensure flag annotations from the spec are + // applied to "conf". + if _, err := specutils.ReadSpec(c.BundleDir, conf); err != nil { + Fatalf("reading spec: %v", err) + } + if err := c.Start(conf); err != nil { Fatalf("starting container: %v", err) } diff --git a/runsc/cmd/state.go b/runsc/cmd/state.go index 2bd2ab9f8..d8a70dd7f 100644 --- a/runsc/cmd/state.go +++ b/runsc/cmd/state.go @@ -57,7 +57,7 @@ func (*State) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) s id := f.Arg(0) conf := args[0].(*config.Config) - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } diff --git a/runsc/cmd/symbolize.go b/runsc/cmd/symbolize.go new file mode 100644 index 000000000..fc0c69358 --- /dev/null +++ b/runsc/cmd/symbolize.go @@ -0,0 +1,91 @@ +// Copyright 2020 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. + +package cmd + +import ( + "bufio" + "context" + "os" + "strconv" + "strings" + + "github.com/google/subcommands" + "gvisor.dev/gvisor/pkg/coverage" + "gvisor.dev/gvisor/runsc/flag" +) + +// Symbolize implements subcommands.Command for the "symbolize" command. +type Symbolize struct { + dumpAll bool +} + +// Name implements subcommands.Command.Name. +func (*Symbolize) Name() string { + return "symbolize" +} + +// Synopsis implements subcommands.Command.Synopsis. +func (*Symbolize) Synopsis() string { + return "Convert synthetic instruction pointers from kcov into positions in the runsc source code. Only used when Go coverage is enabled." +} + +// Usage implements subcommands.Command.Usage. +func (*Symbolize) Usage() string { + return `symbolize - converts synthetic instruction pointers into positions in the runsc source code. + +This command takes instruction pointers from stdin and converts them into their +corresponding file names and line/column numbers in the runsc source code. The +inputs are not interpreted as actual addresses, but as synthetic values that are +exposed through /sys/kernel/debug/kcov. One can extract coverage information +from kcov and translate those values into locations in the source code by +running symbolize on the same runsc binary. +` +} + +// SetFlags implements subcommands.Command.SetFlags. +func (c *Symbolize) SetFlags(f *flag.FlagSet) { + f.BoolVar(&c.dumpAll, "all", false, "dump information on all coverage blocks along with their synthetic PCs") +} + +// Execute implements subcommands.Command.Execute. +func (c *Symbolize) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { + if f.NArg() != 0 { + f.Usage() + return subcommands.ExitUsageError + } + if !coverage.KcovAvailable() { + return Errorf("symbolize can only be used when coverage is available.") + } + coverage.InitCoverageData() + + if c.dumpAll { + coverage.WriteAllBlocks(os.Stdout) + return subcommands.ExitSuccess + } + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + // Input is always base 16, but may or may not have a leading "0x". + str := strings.TrimPrefix(scanner.Text(), "0x") + pc, err := strconv.ParseUint(str, 16 /* base */, 64 /* bitSize */) + if err != nil { + return Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err) + } + if err := coverage.Symbolize(os.Stdout, pc); err != nil { + return Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err) + } + } + return subcommands.ExitSuccess +} diff --git a/runsc/cmd/wait.go b/runsc/cmd/wait.go index 28d0642ed..c1d6aeae2 100644 --- a/runsc/cmd/wait.go +++ b/runsc/cmd/wait.go @@ -72,7 +72,7 @@ func (wt *Wait) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) id := f.Arg(0) conf := args[0].(*config.Config) - c, err := container.Load(conf.RootDir, id) + c, err := container.LoadAndCheck(conf.RootDir, id) if err != nil { Fatalf("loading container: %v", err) } |