From b24d2b8a213c09b511478e7eab5fa343e4a198de Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Mon, 21 Oct 2019 13:25:55 +0100 Subject: vm: Get debug information when FreeBSD on panics (#1470) The FreeBSD kernel debugger can provide more information when the kernel panics. Add support to bhybe and gce to print this information. --- vm/bhyve/bhyve.go | 17 ++++++++++++++++- vm/gce/gce.go | 3 +++ vm/vmimpl/freebsd.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 vm/vmimpl/freebsd.go diff --git a/vm/bhyve/bhyve.go b/vm/bhyve/bhyve.go index 36177dac6..0000e2c27 100644 --- a/vm/bhyve/bhyve.go +++ b/vm/bhyve/bhyve.go @@ -49,6 +49,7 @@ type instance struct { merger *vmimpl.OutputMerger vmName string bhyve *exec.Cmd + consolew io.WriteCloser } var ipRegex = regexp.MustCompile(`bound to (([0-9]+\.){3}[0-9]+) `) @@ -177,17 +178,28 @@ func (inst *instance) Boot() error { if err != nil { return err } + inr, inw, err := osutil.LongPipe() + if err != nil { + outr.Close() + outw.Close() + return err + } bhyve := osutil.Command("bhyve", bhyveArgs...) + bhyve.Stdin = inr bhyve.Stdout = outw bhyve.Stderr = outw if err := bhyve.Start(); err != nil { outr.Close() outw.Close() + inr.Close() + inw.Close() return err } outw.Close() outw = nil + inst.consolew = inw + inr.Close() inst.bhyve = bhyve var tee io.Writer @@ -245,6 +257,9 @@ func (inst *instance) Boot() error { } func (inst *instance) Close() { + if inst.consolew != nil { + inst.consolew.Close() + } if inst.bhyve != nil { inst.bhyve.Process.Kill() inst.bhyve.Wait() @@ -331,7 +346,7 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin } func (inst *instance) Diagnose() ([]byte, bool) { - return nil, false + return nil, vmimpl.DiagnoseFreeBSD(inst.consolew) } func parseIP(output []byte) string { diff --git a/vm/gce/gce.go b/vm/gce/gce.go index cad34addf..98ab494dd 100644 --- a/vm/gce/gce.go +++ b/vm/gce/gce.go @@ -370,6 +370,9 @@ func waitForConsoleConnect(merger *vmimpl.OutputMerger) error { } func (inst *instance) Diagnose() ([]byte, bool) { + if inst.env.OS == "freebsd" { + return nil, vmimpl.DiagnoseFreeBSD(inst.consolew) + } if inst.env.OS == "openbsd" { return nil, vmimpl.DiagnoseOpenBSD(inst.consolew) } diff --git a/vm/vmimpl/freebsd.go b/vm/vmimpl/freebsd.go new file mode 100644 index 000000000..c6074028a --- /dev/null +++ b/vm/vmimpl/freebsd.go @@ -0,0 +1,32 @@ +// Copyright 2018 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package vmimpl + +import ( + "io" + "time" +) + +// DiagnoseFreeBSD sends the debug commands to the given writer which +// is expected to be connected to a panicked FreeBSD kernel. If kernel +// just hanged, we've lost connection or detected some non-panic +// error, console still shows normal login prompt. +func DiagnoseFreeBSD(w io.Writer) bool { + commands := []string{ + "", + "set $lines = 0", // disable pagination + "set $maxwidth = 0", // disable line continuation + "show registers", + "show proc", + "ps", + "show all locks", + "show malloc", + "show ktr", + } + for _, c := range commands { + w.Write([]byte(c + "\n")) + time.Sleep(1 * time.Second) + } + return true +} -- cgit mrf-deployment