diff options
-rw-r--r-- | scripts/kconfig/symbol.c | 142 |
1 files changed, 127 insertions, 15 deletions
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 9f180ab7698d..bc1e1584e2da 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c | |||
@@ -783,6 +783,110 @@ struct symbol **sym_re_search(const char *pattern) | |||
783 | return sym_arr; | 783 | return sym_arr; |
784 | } | 784 | } |
785 | 785 | ||
786 | /* | ||
787 | * When we check for recursive dependencies we use a stack to save | ||
788 | * current state so we can print out relevant info to user. | ||
789 | * The entries are located on the call stack so no need to free memory. | ||
790 | * Note inser() remove() must always match to properly clear the stack. | ||
791 | */ | ||
792 | static struct dep_stack { | ||
793 | struct dep_stack *prev, *next; | ||
794 | struct symbol *sym; | ||
795 | struct property *prop; | ||
796 | struct expr *expr; | ||
797 | } *check_top; | ||
798 | |||
799 | static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) | ||
800 | { | ||
801 | memset(stack, 0, sizeof(*stack)); | ||
802 | if (check_top) | ||
803 | check_top->next = stack; | ||
804 | stack->prev = check_top; | ||
805 | stack->sym = sym; | ||
806 | check_top = stack; | ||
807 | } | ||
808 | |||
809 | static void dep_stack_remove(void) | ||
810 | { | ||
811 | check_top = check_top->prev; | ||
812 | if (check_top) | ||
813 | check_top->next = NULL; | ||
814 | } | ||
815 | |||
816 | /* | ||
817 | * Called when we have detected a recursive dependency. | ||
818 | * check_top point to the top of the stact so we use | ||
819 | * the ->prev pointer to locate the bottom of the stack. | ||
820 | */ | ||
821 | static void sym_check_print_recursive(struct symbol *last_sym) | ||
822 | { | ||
823 | struct dep_stack *stack; | ||
824 | struct symbol *sym, *next_sym; | ||
825 | struct menu *menu = NULL; | ||
826 | struct property *prop; | ||
827 | struct dep_stack cv_stack; | ||
828 | |||
829 | if (sym_is_choice_value(last_sym)) { | ||
830 | dep_stack_insert(&cv_stack, last_sym); | ||
831 | last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); | ||
832 | } | ||
833 | |||
834 | for (stack = check_top; stack != NULL; stack = stack->prev) | ||
835 | if (stack->sym == last_sym) | ||
836 | break; | ||
837 | if (!stack) { | ||
838 | fprintf(stderr, "unexpected recursive dependency error\n"); | ||
839 | return; | ||
840 | } | ||
841 | |||
842 | for (; stack; stack = stack->next) { | ||
843 | sym = stack->sym; | ||
844 | next_sym = stack->next ? stack->next->sym : last_sym; | ||
845 | prop = stack->prop; | ||
846 | |||
847 | /* for choice values find the menu entry (used below) */ | ||
848 | if (sym_is_choice(sym) || sym_is_choice_value(sym)) { | ||
849 | for (prop = sym->prop; prop; prop = prop->next) { | ||
850 | menu = prop->menu; | ||
851 | if (prop->menu) | ||
852 | break; | ||
853 | } | ||
854 | } | ||
855 | if (stack->sym == last_sym) | ||
856 | fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", | ||
857 | prop->file->name, prop->lineno); | ||
858 | if (stack->expr) { | ||
859 | fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", | ||
860 | prop->file->name, prop->lineno, | ||
861 | sym->name ? sym->name : "<choice>", | ||
862 | prop_get_type_name(prop->type), | ||
863 | next_sym->name ? next_sym->name : "<choice>"); | ||
864 | } else if (stack->prop) { | ||
865 | fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", | ||
866 | prop->file->name, prop->lineno, | ||
867 | sym->name ? sym->name : "<choice>", | ||
868 | next_sym->name ? next_sym->name : "<choice>"); | ||
869 | } else if (sym_is_choice(sym)) { | ||
870 | fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", | ||
871 | menu->file->name, menu->lineno, | ||
872 | sym->name ? sym->name : "<choice>", | ||
873 | next_sym->name ? next_sym->name : "<choice>"); | ||
874 | } else if (sym_is_choice_value(sym)) { | ||
875 | fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", | ||
876 | menu->file->name, menu->lineno, | ||
877 | sym->name ? sym->name : "<choice>", | ||
878 | next_sym->name ? next_sym->name : "<choice>"); | ||
879 | } else { | ||
880 | fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", | ||
881 | prop->file->name, prop->lineno, | ||
882 | sym->name ? sym->name : "<choice>", | ||
883 | next_sym->name ? next_sym->name : "<choice>"); | ||
884 | } | ||
885 | } | ||
886 | |||
887 | if (check_top == &cv_stack) | ||
888 | dep_stack_remove(); | ||
889 | } | ||
786 | 890 | ||
787 | static struct symbol *sym_check_expr_deps(struct expr *e) | 891 | static struct symbol *sym_check_expr_deps(struct expr *e) |
788 | { | 892 | { |
@@ -819,24 +923,33 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) | |||
819 | { | 923 | { |
820 | struct symbol *sym2; | 924 | struct symbol *sym2; |
821 | struct property *prop; | 925 | struct property *prop; |
926 | struct dep_stack stack; | ||
927 | |||
928 | dep_stack_insert(&stack, sym); | ||
822 | 929 | ||
823 | sym2 = sym_check_expr_deps(sym->rev_dep.expr); | 930 | sym2 = sym_check_expr_deps(sym->rev_dep.expr); |
824 | if (sym2) | 931 | if (sym2) |
825 | return sym2; | 932 | goto out; |
826 | 933 | ||
827 | for (prop = sym->prop; prop; prop = prop->next) { | 934 | for (prop = sym->prop; prop; prop = prop->next) { |
828 | if (prop->type == P_CHOICE || prop->type == P_SELECT) | 935 | if (prop->type == P_CHOICE || prop->type == P_SELECT) |
829 | continue; | 936 | continue; |
937 | stack.prop = prop; | ||
830 | sym2 = sym_check_expr_deps(prop->visible.expr); | 938 | sym2 = sym_check_expr_deps(prop->visible.expr); |
831 | if (sym2) | 939 | if (sym2) |
832 | break; | 940 | break; |
833 | if (prop->type != P_DEFAULT || sym_is_choice(sym)) | 941 | if (prop->type != P_DEFAULT || sym_is_choice(sym)) |
834 | continue; | 942 | continue; |
943 | stack.expr = prop->expr; | ||
835 | sym2 = sym_check_expr_deps(prop->expr); | 944 | sym2 = sym_check_expr_deps(prop->expr); |
836 | if (sym2) | 945 | if (sym2) |
837 | break; | 946 | break; |
947 | stack.expr = NULL; | ||
838 | } | 948 | } |
839 | 949 | ||
950 | out: | ||
951 | dep_stack_remove(); | ||
952 | |||
840 | return sym2; | 953 | return sym2; |
841 | } | 954 | } |
842 | 955 | ||
@@ -845,6 +958,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice) | |||
845 | struct symbol *sym, *sym2; | 958 | struct symbol *sym, *sym2; |
846 | struct property *prop; | 959 | struct property *prop; |
847 | struct expr *e; | 960 | struct expr *e; |
961 | struct dep_stack stack; | ||
962 | |||
963 | dep_stack_insert(&stack, choice); | ||
848 | 964 | ||
849 | prop = sym_get_choice_prop(choice); | 965 | prop = sym_get_choice_prop(choice); |
850 | expr_list_for_each_sym(prop->expr, e, sym) | 966 | expr_list_for_each_sym(prop->expr, e, sym) |
@@ -858,10 +974,8 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice) | |||
858 | 974 | ||
859 | expr_list_for_each_sym(prop->expr, e, sym) { | 975 | expr_list_for_each_sym(prop->expr, e, sym) { |
860 | sym2 = sym_check_sym_deps(sym); | 976 | sym2 = sym_check_sym_deps(sym); |
861 | if (sym2) { | 977 | if (sym2) |
862 | fprintf(stderr, " -> %s", sym->name); | ||
863 | break; | 978 | break; |
864 | } | ||
865 | } | 979 | } |
866 | out: | 980 | out: |
867 | expr_list_for_each_sym(prop->expr, e, sym) | 981 | expr_list_for_each_sym(prop->expr, e, sym) |
@@ -871,6 +985,8 @@ out: | |||
871 | prop_get_symbol(sym_get_choice_prop(sym2)) == choice) | 985 | prop_get_symbol(sym_get_choice_prop(sym2)) == choice) |
872 | sym2 = choice; | 986 | sym2 = choice; |
873 | 987 | ||
988 | dep_stack_remove(); | ||
989 | |||
874 | return sym2; | 990 | return sym2; |
875 | } | 991 | } |
876 | 992 | ||
@@ -880,18 +996,20 @@ struct symbol *sym_check_deps(struct symbol *sym) | |||
880 | struct property *prop; | 996 | struct property *prop; |
881 | 997 | ||
882 | if (sym->flags & SYMBOL_CHECK) { | 998 | if (sym->flags & SYMBOL_CHECK) { |
883 | fprintf(stderr, "%s:%d:error: found recursive dependency: %s", | 999 | sym_check_print_recursive(sym); |
884 | sym->prop->file->name, sym->prop->lineno, | ||
885 | sym->name ? sym->name : "<choice>"); | ||
886 | return sym; | 1000 | return sym; |
887 | } | 1001 | } |
888 | if (sym->flags & SYMBOL_CHECKED) | 1002 | if (sym->flags & SYMBOL_CHECKED) |
889 | return NULL; | 1003 | return NULL; |
890 | 1004 | ||
891 | if (sym_is_choice_value(sym)) { | 1005 | if (sym_is_choice_value(sym)) { |
1006 | struct dep_stack stack; | ||
1007 | |||
892 | /* for choice groups start the check with main choice symbol */ | 1008 | /* for choice groups start the check with main choice symbol */ |
1009 | dep_stack_insert(&stack, sym); | ||
893 | prop = sym_get_choice_prop(sym); | 1010 | prop = sym_get_choice_prop(sym); |
894 | sym2 = sym_check_deps(prop_get_symbol(prop)); | 1011 | sym2 = sym_check_deps(prop_get_symbol(prop)); |
1012 | dep_stack_remove(); | ||
895 | } else if (sym_is_choice(sym)) { | 1013 | } else if (sym_is_choice(sym)) { |
896 | sym2 = sym_check_choice_deps(sym); | 1014 | sym2 = sym_check_choice_deps(sym); |
897 | } else { | 1015 | } else { |
@@ -900,14 +1018,8 @@ struct symbol *sym_check_deps(struct symbol *sym) | |||
900 | sym->flags &= ~SYMBOL_CHECK; | 1018 | sym->flags &= ~SYMBOL_CHECK; |
901 | } | 1019 | } |
902 | 1020 | ||
903 | if (sym2) { | 1021 | if (sym2 && sym2 == sym) |
904 | fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>"); | 1022 | sym2 = NULL; |
905 | if (sym2 == sym) { | ||
906 | fprintf(stderr, "\n"); | ||
907 | zconfnerrs++; | ||
908 | sym2 = NULL; | ||
909 | } | ||
910 | } | ||
911 | 1023 | ||
912 | return sym2; | 1024 | return sym2; |
913 | } | 1025 | } |