From f03c419189ef8ed823e306a342ee4d330fb2c394 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 4 Feb 2026 08:29:34 +0100 Subject: pkg/aflow/action/crash: handle boot errors better Provide better errors messages on boot errors. --- pkg/aflow/action/crash/reproduce.go | 37 ++++++++++++++++++++++++++++++++----- pkg/aflow/action/crash/test.go | 4 ++-- 2 files changed, 34 insertions(+), 7 deletions(-) (limited to 'pkg') diff --git a/pkg/aflow/action/crash/reproduce.go b/pkg/aflow/action/crash/reproduce.go index cb625af08..7e194a3e3 100644 --- a/pkg/aflow/action/crash/reproduce.go +++ b/pkg/aflow/action/crash/reproduce.go @@ -44,6 +44,13 @@ type reproduceResult struct { CrashReport string } +// ReproduceCrash tests reproducer and returns: +// - Report: if the reproducer caused the kernel crash +// - boot failure: if the kernel failed to boot or function properly +// (if kernel crashed during build/boot, the Report is not returned) +// - error: for unexpected failures +// +// All 3 values are empty, if everything went well, and kernel has not crashed. func ReproduceCrash(args ReproduceArgs, workdir string) (*report.Report, string, error) { if args.Type != "qemu" { return nil, "", errors.New("only qemu VM type is supported") @@ -78,20 +85,40 @@ func ReproduceCrash(args ReproduceArgs, workdir string) (*report.Report, string, if err != nil { return nil, "", err } + // TODO: run multiple instances, handle TestError.Infra, and aggregate results. results, err := env.Test(1, nil, nil, []byte(args.ReproC)) if err != nil { return nil, "", err } - if results[0].Error != nil { - if crashErr := new(instance.CrashError); errors.As(results[0].Error, &crashErr) { + if err := results[0].Error; err != nil { + if crashErr := new(instance.CrashError); errors.As(err, &crashErr) { return crashErr.Report, "", nil + } else if testErr := new(instance.TestError); errors.As(err, &testErr) { + return parseTestError(testErr) } else { - return nil, results[0].Error.Error(), nil + return nil, err.Error(), nil } } return nil, "", nil } +func parseTestError(err *instance.TestError) (*report.Report, string, error) { + if err.Infra { + // No point in showing this to LLM and asking to fix. + return nil, "", fmt.Errorf("%v\n%v\n%s", err.Error(), err.Title, err.Output) + } + what := "Basic kernel testing failed" + if err.Boot { + what = "Kernel failed to boot" + } + extraInfo := err.Output + // Don't use TestError.Report for crashes like "lost connection" that don't have a report. + if err.Report != nil && err.Report.Report != nil { + extraInfo = err.Report.Report + } + return nil, fmt.Sprintf("%v: %v\n%s", what, err.Title, extraInfo), nil +} + func reproduce(ctx *aflow.Context, args ReproduceArgs) (reproduceResult, error) { imageData, err := os.ReadFile(args.Image) if err != nil { @@ -112,12 +139,12 @@ func reproduce(ctx *aflow.Context, args ReproduceArgs) (reproduceResult, error) if err != nil { return res, err } - rep, buildError, err := ReproduceCrash(args, workdir) + rep, bootError, err := ReproduceCrash(args, workdir) if rep != nil { res.BugTitle = rep.Title res.Report = string(rep.Report) } - res.Error = buildError + res.Error = bootError return res, err }) if err != nil { diff --git a/pkg/aflow/action/crash/test.go b/pkg/aflow/action/crash/test.go index b479cfde0..2eda9b84c 100644 --- a/pkg/aflow/action/crash/test.go +++ b/pkg/aflow/action/crash/test.go @@ -94,11 +94,11 @@ func testPatch(ctx *aflow.Context, args testArgs) (testResult, error) { KernelCommit: args.KernelCommit, KernelConfig: args.KernelConfig, } - rep, reportLog, err := ReproduceCrash(reproduceArgs, workdir) + rep, bootError, err := ReproduceCrash(reproduceArgs, workdir) if rep != nil { res.TestError = string(rep.Report) } else { - res.TestError = reportLog + res.TestError = bootError } return res, err }) -- cgit mrf-deployment