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 | } |
