aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/kconfig/kconfig.go51
-rw-r--r--pkg/kconfig/kconfig_test.go32
-rw-r--r--tools/syz-kconf/kconf.go12
3 files changed, 86 insertions, 9 deletions
diff --git a/pkg/kconfig/kconfig.go b/pkg/kconfig/kconfig.go
index 021929781..7cb54a1bb 100644
--- a/pkg/kconfig/kconfig.go
+++ b/pkg/kconfig/kconfig.go
@@ -30,13 +30,15 @@ type Menu struct {
Elems []*Menu // sub-elements for menus
Parent *Menu // parent menu, non-nil for everythign except for mainmenu
- kconf *KConfig // back-link to the owning KConfig
- prompts []prompt
- defaults []defaultVal
- dependsOn expr
- visibleIf expr
- deps map[string]bool
- depsOnce sync.Once
+ kconf *KConfig // back-link to the owning KConfig
+ prompts []prompt
+ defaults []defaultVal
+ dependsOn expr
+ visibleIf expr
+ deps map[string]bool
+ depsOnce sync.Once
+ selects []string
+ selectedBy []string // filled in in setSelectedBy()
}
type prompt struct {
@@ -144,6 +146,7 @@ func ParseData(target *targets.Target, data []byte, file string) (*KConfig, erro
Configs: make(map[string]*Menu),
}
kconf.walk(root, nil, nil)
+ kconf.setSelectedBy()
return kconf, nil
}
@@ -159,6 +162,37 @@ func (kconf *KConfig) walk(m *Menu, dependsOn, visibleIf expr) {
}
}
+// NOTE: the function is ignoring the "if" part of select/imply.
+func (kconf *KConfig) setSelectedBy() {
+ for name, cfg := range kconf.Configs {
+ for _, selectedName := range cfg.selects {
+ selected := kconf.Configs[selectedName]
+ if selected == nil {
+ continue
+ }
+ selected.selectedBy = append(selected.selectedBy, name)
+ }
+ }
+}
+
+// NOTE: the function is ignoring the "if" part of select/imply.
+func (kconf *KConfig) SelectedBy(name string) map[string]bool {
+ ret := map[string]bool{}
+ toVisit := []string{name}
+ for len(toVisit) > 0 {
+ next := kconf.Configs[toVisit[len(toVisit)-1]]
+ toVisit = toVisit[:len(toVisit)-1]
+ if next == nil {
+ continue
+ }
+ for _, selectedBy := range next.selectedBy {
+ ret[selectedBy] = true
+ toVisit = append(toVisit, selectedBy)
+ }
+ }
+ return ret
+}
+
func (kp *kconfigParser) parseFile() {
for kp.nextLine() {
kp.parseLine()
@@ -293,7 +327,8 @@ func (kp *kconfigParser) parseProperty(prop string) {
kp.MustConsume("if")
cur.visibleIf = exprAnd(cur.visibleIf, kp.parseExpr())
case "select", "imply":
- _ = kp.Ident()
+ name := kp.Ident()
+ cur.selects = append(cur.selects, name)
if kp.TryConsume("if") {
_ = kp.parseExpr()
}
diff --git a/pkg/kconfig/kconfig_test.go b/pkg/kconfig/kconfig_test.go
index 994f1856f..44eda3168 100644
--- a/pkg/kconfig/kconfig_test.go
+++ b/pkg/kconfig/kconfig_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"github.com/google/syzkaller/sys/targets"
+ "github.com/stretchr/testify/assert"
)
func TestParseKConfig(t *testing.T) {
@@ -35,6 +36,37 @@ config FOO
}
}
+func TestSelectedby(t *testing.T) {
+ configData := `
+mainmenu "test"
+
+config FEATURE_A
+ bool "Feature A"
+ select FEATURE_B
+
+config FEATURE_B
+ bool "Feature B"
+ select FEATURE_C
+
+config FEATURE_C
+ bool "Feature C"
+
+`
+ target := targets.Get("linux", "amd64")
+ kconf, err := ParseData(target, []byte(configData), "Kconfig")
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Empty(t, kconf.SelectedBy("FEATURE_A"))
+ assert.Equal(t, map[string]bool{
+ "FEATURE_A": true,
+ }, kconf.SelectedBy("FEATURE_B"))
+ assert.Equal(t, map[string]bool{
+ "FEATURE_A": true,
+ "FEATURE_B": true,
+ }, kconf.SelectedBy("FEATURE_C"))
+}
+
func TestFuzzParseKConfig(t *testing.T) {
for _, data := range []string{
``,
diff --git a/tools/syz-kconf/kconf.go b/tools/syz-kconf/kconf.go
index 5a8808a11..ac9392e8e 100644
--- a/tools/syz-kconf/kconf.go
+++ b/tools/syz-kconf/kconf.go
@@ -315,7 +315,17 @@ func (ctx *Context) verifyConfigs(cf *kconfig.ConfigFile) error {
if act == kconfig.No {
errs.push("%v:%v: %v is not present in the final config", cfg.File, cfg.Line, cfg.Name)
} else if cfg.Value == kconfig.No {
- errs.push("%v:%v: %v is present in the final config", cfg.File, cfg.Line, cfg.Name)
+ var selectedBy []string
+ for name := range ctx.Kconf.SelectedBy(cfg.Name) {
+ if cf.Value(name) == kconfig.Yes {
+ selectedBy = append(selectedBy, name)
+ }
+ }
+ selectedByStr := ""
+ if len(selectedBy) > 0 {
+ selectedByStr = fmt.Sprintf(", possibly selected by %q", selectedBy)
+ }
+ errs.push("%v:%v: %v is present in the final config%s", cfg.File, cfg.Line, cfg.Name, selectedByStr)
} else {
errs.push("%v:%v: %v does not match final config %v vs %v",
cfg.File, cfg.Line, cfg.Name, cfg.Value, act)