From 8f58e4babeecd6606f4c9729919cc85c470bc422 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 17 Oct 2020 20:00:45 +0200 Subject: pkg/bisect: switch to kconfig.Minimize Use the new kconfig.Minimize for config minization instead of the config-bisect.pl script. This is mostly just deleting code. Also update tests: - minimization is now supposed to test the baseline config (update "testos" stub accordingly) - minimization is not supposed to return a config that does not build (a reasonable config minimization procedure can't arrive to such config), remove test that tests this Update #2171 --- pkg/vcs/linux.go | 170 ++++++------------------------------------------------- 1 file changed, 16 insertions(+), 154 deletions(-) (limited to 'pkg/vcs/linux.go') diff --git a/pkg/vcs/linux.go b/pkg/vcs/linux.go index fc57532cb..b3c22e0d6 100644 --- a/pkg/vcs/linux.go +++ b/pkg/vcs/linux.go @@ -4,13 +4,10 @@ package vcs import ( - "bufio" "bytes" "fmt" "io" - "io/ioutil" "net/mail" - "os" "path/filepath" "regexp" "sort" @@ -304,166 +301,31 @@ func (ctx *linux) Minimize(original, baseline []byte, trace io.Writer, fmt.Fprintf(trace, "# configuration already minimized\n") return original, nil } - bisectDir, err := ioutil.TempDir("", "syz-config-bisect") + kconf, err := kconfig.Parse(filepath.Join(ctx.git.dir, "Kconfig")) if err != nil { - return nil, fmt.Errorf("failed to create temp dir for config bisect: %v", err) + return nil, fmt.Errorf("failed to parse Kconfig: %v", err) } - defer os.RemoveAll(bisectDir) - kernelConfig := filepath.Join(bisectDir, "kernel.config") - kernelBaselineConfig := filepath.Join(bisectDir, "kernel.baseline_config") - if err := ctx.prepareConfigBisectEnv(kernelConfig, kernelBaselineConfig, original, baseline); err != nil { - return nil, err - } - - fmt.Fprintf(trace, "# start config bisection\n") - configBisect := filepath.Join(ctx.git.dir, "tools", "testing", "ktest", "config-bisect.pl") - output, err := osutil.RunCmd(time.Hour, "", configBisect, - "-l", ctx.git.dir, "-r", "-b", ctx.git.dir, kernelBaselineConfig, kernelConfig) + originalConfig, err := kconfig.ParseConfigData(original, "original") if err != nil { - return nil, fmt.Errorf("config bisect failed: %v", err) - } - fmt.Fprintf(trace, "# config-bisect.pl -r:\n%s", output) - for { - config, err := ioutil.ReadFile(filepath.Join(ctx.git.dir, ".config")) - if err != nil { - return nil, fmt.Errorf("failed to read .config: %v", err) - } - - testRes, err := pred(config) - if err != nil { - return nil, err - } - if testRes == BisectSkip { - return nil, fmt.Errorf("unable to test, stopping config bisection") - } - verdict := "good" - if testRes == BisectBad { - verdict = "bad" - } - - output1, err := osutil.RunCmd(time.Hour, "", configBisect, - "-l", ctx.git.dir, "-b", ctx.git.dir, kernelBaselineConfig, kernelConfig, verdict) - fmt.Fprintf(trace, "# config-bisect.pl %v:\n%s", verdict, output1) - output = append(output, output1...) - if err != nil { - if verr, ok := err.(*osutil.VerboseError); ok && verr.ExitCode == 2 { - break - } - return nil, fmt.Errorf("config bisect failed: %v", err) - } - } - fmt.Fprintf(trace, "# config_bisect.pl finished\n") - configOptions := ctx.parseConfigBisectLog(trace, output) - if len(configOptions) == 0 { - return nil, fmt.Errorf("no config changes in the config bisect log:\n%s", output) - } - - // Parse minimalistic configuration to generate the crash. - minimizedConfig, err := ctx.generateMinConfig(configOptions, bisectDir, kernelBaselineConfig) - if err != nil { - return nil, fmt.Errorf("generating minimized config failed: %v", err) - } - return minimizedConfig, nil -} - -func (ctx *linux) prepareConfigBisectEnv(kernelConfig, kernelBaselineConfig string, original, baseline []byte) error { - current, err := ctx.HeadCommit() - if err != nil { - return err + return nil, err } - - // Call EnvForCommit if some options needs to be adjusted. - bisectEnv, err := ctx.EnvForCommit("", current.Hash, original) + baselineConfig, err := kconfig.ParseConfigData(baseline, "baseline") if err != nil { - return fmt.Errorf("failed create commit environment: %v", err) + return nil, err } - if err := osutil.WriteFile(kernelConfig, bisectEnv.KernelConfig); err != nil { - return fmt.Errorf("failed to write config file: %v", err) + linuxAlterConfigs(originalConfig, nil) + linuxAlterConfigs(baselineConfig, nil) + kconfPred := func(candidate *kconfig.ConfigFile) (bool, error) { + res, err := pred(serialize(candidate)) + return res == BisectBad, err } - - // Call EnvForCommit again if some options needs to be adjusted in baseline. - bisectEnv, err = ctx.EnvForCommit("", current.Hash, baseline) + minConfig, err := kconf.Minimize(baselineConfig, originalConfig, kconfPred, trace) if err != nil { - return fmt.Errorf("failed create commit environment: %v", err) - } - if err := osutil.WriteFile(kernelBaselineConfig, bisectEnv.KernelConfig); err != nil { - return fmt.Errorf("failed to write minimum config file: %v", err) - } - return nil -} - -// Takes in config_bisect.pl output: -// Hmm, can't make any more changes without making good == bad? -// Difference between good (+) and bad (-) -// +DRIVER1=n -// +DRIVER2=n -// -DRIVER3=n -// -DRIVER4=n -// DRIVER5 n -> y -// DRIVER6 y -> n -// See good and bad configs for details: -// good: /mnt/work/linux/good_config.tmp -// bad: /mnt/work/linux/bad_config.tmp -func (ctx *linux) parseConfigBisectLog(trace io.Writer, bisectLog []byte) []string { - var configOptions []string - start := false - for s := bufio.NewScanner(bytes.NewReader(bisectLog)); s.Scan(); { - line := s.Text() - if strings.Contains(line, "See good and bad configs for details:") { - break - } - if !start { - if strings.Contains(line, "Difference between good (+) and bad (-)") { - start = true - } - continue - } - if strings.HasPrefix(line, "+") { - // This is option only in good config. Drop it as it's dependent - // on some option which is disabled in bad config. - continue - } - option, selection := "", "" - if strings.HasPrefix(line, "-") { - // -CONFIG_DRIVER_1=n - // Remove preceding -1 and split to option and selection - fields := strings.Split(strings.TrimPrefix(line, "-"), "=") - option = fields[0] - selection = fields[len(fields)-1] - } else { - // DRIVER_OPTION1 n -> y - fields := strings.Split(strings.TrimPrefix(line, " "), " ") - option = fields[0] - selection = fields[len(fields)-1] - } - - configOptioon := "CONFIG_" + option + "=" + selection - if selection == "n" { - configOptioon = "# CONFIG_" + option + " is not set" - } - configOptions = append(configOptions, configOptioon) + return nil, err } - - fmt.Fprintf(trace, "# found config option changes %v\n", configOptions) - return configOptions + return serialize(minConfig), nil } -func (ctx *linux) generateMinConfig(configOptions []string, outdir, baseline string) ([]byte, error) { - kernelAdditionsConfig := filepath.Join(outdir, "kernel.additions_config") - if err := osutil.WriteFile(kernelAdditionsConfig, []byte(strings.Join(configOptions, "\n"))); err != nil { - return nil, fmt.Errorf("failed to write config additions file: %v", err) - } - - _, err := osutil.RunCmd(time.Hour, "", filepath.Join(ctx.git.dir, "scripts", "kconfig", "merge_config.sh"), - "-m", "-O", outdir, baseline, kernelAdditionsConfig) - if err != nil { - return nil, fmt.Errorf("config merge failed: %v", err) - } - - minConfig, err := ioutil.ReadFile(filepath.Join(outdir, ".config")) - if err != nil { - return nil, fmt.Errorf("failed to read merged configuration: %v", err) - } - minConfig = append([]byte(fmt.Sprintf("%v, rev: %v\n", configBisectTag, prog.GitRevision)), minConfig...) - return minConfig, nil +func serialize(cf *kconfig.ConfigFile) []byte { + return []byte(fmt.Sprintf("%v, rev: %v\n%s", configBisectTag, prog.GitRevision, cf.Serialize())) } -- cgit mrf-deployment