[PATCH 2/2] Allow toggling of semantic checks
David Gibson
david at gibson.dropbear.id.au
Sun Jul 8 23:25:22 EST 2012
This patch adds -W and -E options to dtc which allow toggling on and off
of the various built in semantic checks on the tree.
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
---
checks.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--
dtc.c | 13 +++++++-
dtc.h | 1 +
tests/dtc-checkfails.sh | 20 +++++++++--
tests/dtc-fails.sh | 30 +++++++++++++++++
tests/run_tests.sh | 12 +++++++
6 files changed, 154 insertions(+), 6 deletions(-)
create mode 100755 tests/dtc-fails.sh
diff --git a/checks.c b/checks.c
index 3080439..9061237 100644
--- a/checks.c
+++ b/checks.c
@@ -58,7 +58,7 @@ struct check {
struct check **prereq;
};
-#define CHECK(nm, tfn, nfn, pfn, d, w, e, ...) \
+#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
static struct check nm = { \
.name = #nm, \
@@ -73,22 +73,30 @@ struct check {
.prereq = nm##_prereqs, \
};
#define WARNING(nm, tfn, nfn, pfn, d, ...) \
- CHECK(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
+ CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
#define ERROR(nm, tfn, nfn, pfn, d, ...) \
- CHECK(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
+ CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
+#define CHECK(nm, tfn, nfn, pfn, d, ...) \
+ CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__)
#define TREE_WARNING(nm, d, ...) \
WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define TREE_ERROR(nm, d, ...) \
ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
+#define TREE_CHECK(nm, d, ...) \
+ CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define NODE_WARNING(nm, d, ...) \
WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define NODE_ERROR(nm, d, ...) \
ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
+#define NODE_CHECK(nm, d, ...) \
+ CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define PROP_WARNING(nm, d, ...) \
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#define PROP_ERROR(nm, d, ...) \
ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
+#define PROP_CHECK(nm, d, ...) \
+ CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#ifdef __GNUC__
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
@@ -179,6 +187,13 @@ out:
* Utility check functions
*/
+/* A check which always fails, for testing purposes only */
+static inline void check_always_fail(struct check *c, struct node *dt)
+{
+ FAIL(c, "always_fail check");
+}
+TREE_CHECK(always_fail, NULL);
+
static void check_is_string(struct check *c, struct node *root,
struct node *node)
{
@@ -649,8 +664,71 @@ static struct check *check_table[] = {
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,
+
+ &always_fail,
};
+static void enable_warning_error(struct check *c, bool warn, bool error)
+{
+ int i;
+
+ /* Raising level, also raise it for prereqs */
+ if ((warn && !c->warn) || (error && !c->error))
+ for (i = 0; i < c->num_prereqs; i++)
+ enable_warning_error(c->prereq[i], warn, error);
+
+ c->warn = c->warn || warn;
+ c->error = c->error || error;
+}
+
+static void disable_warning_error(struct check *c, bool warn, bool error)
+{
+ int i;
+
+ /* Lowering level, also lower it for things this is the prereq
+ * for */
+ if ((warn && c->warn) || (error && c->error)) {
+ for (i = 0; i < ARRAY_SIZE(check_table); i++) {
+ struct check *cc = check_table[i];
+ int j;
+
+ for (j = 0; j < cc->num_prereqs; j++)
+ if (cc->prereq[j] == c)
+ disable_warning_error(cc, warn, error);
+ }
+ }
+
+ c->warn = c->warn && !warn;
+ c->error = c->error && !error;
+}
+
+void parse_checks_option(bool warn, bool error, const char *optarg)
+{
+ int i;
+ const char *name = optarg;
+ bool enable = true;
+
+ if ((strncmp(optarg, "no-", 3) == 0)
+ || (strncmp(optarg, "no_", 3) == 0)) {
+ name = optarg + 3;
+ enable = false;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(check_table); i++) {
+ struct check *c = check_table[i];
+
+ if (streq(c->name, name)) {
+ if (enable)
+ enable_warning_error(c, warn, error);
+ else
+ disable_warning_error(c, warn, error);
+ return;
+ }
+ }
+
+ die("Unrecognized check name \"%s\"\n", name);
+}
+
void process_checks(int force, struct boot_info *bi)
{
struct node *dt = bi->dt;
diff --git a/dtc.c b/dtc.c
index bee5085..a375683 100644
--- a/dtc.c
+++ b/dtc.c
@@ -93,6 +93,9 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
+ fprintf(stderr, "\t-W [no-]<checkname>\n");
+ fprintf(stderr, "\t-E [no-]<checkname>\n");
+ fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
exit(3);
}
@@ -115,7 +118,7 @@ int main(int argc, char *argv[])
minsize = 0;
padsize = 0;
- while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:s"))
+ while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
!= EOF) {
switch (opt) {
case 'I':
@@ -173,6 +176,14 @@ int main(int argc, char *argv[])
sort = 1;
break;
+ case 'W':
+ parse_checks_option(true, false, optarg);
+ break;
+
+ case 'E':
+ parse_checks_option(false, true, optarg);
+ break;
+
case 'h':
default:
usage();
diff --git a/dtc.h b/dtc.h
index d57fbfc..7ee2d54 100644
--- a/dtc.h
+++ b/dtc.h
@@ -226,6 +226,7 @@ void sort_tree(struct boot_info *bi);
/* Checks */
+void parse_checks_option(bool warn, bool error, const char *optarg);
void process_checks(int force, struct boot_info *bi);
/* Flattened trees */
diff --git a/tests/dtc-checkfails.sh b/tests/dtc-checkfails.sh
index 3f77b13..76ded15 100755
--- a/tests/dtc-checkfails.sh
+++ b/tests/dtc-checkfails.sh
@@ -4,10 +4,20 @@
for x; do
shift
+ if [ "$x" = "-n" ]; then
+ for x; do
+ shift
+ if [ "$x" = "--" ]; then
+ break;
+ fi
+ NOCHECKS="$NOCHECKS $x"
+ done
+ break;
+ fi
if [ "$x" = "--" ]; then
break;
fi
- CHECKS="$CHECKS $x"
+ YESCHECKS="$YESCHECKS $x"
done
LOG=tmp.log.$$
@@ -19,10 +29,16 @@ ret="$?"
FAIL_IF_SIGNAL $ret
-for c in $CHECKS; do
+for c in $YESCHECKS; do
if ! grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
FAIL "Failed to trigger check \"$c\""
fi
done
+for c in $NOCHECKS; do
+ if grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
+ FAIL "Incorrectly triggered check \"$c\""
+ fi
+done
+
PASS
diff --git a/tests/dtc-fails.sh b/tests/dtc-fails.sh
new file mode 100755
index 0000000..4ddcb27
--- /dev/null
+++ b/tests/dtc-fails.sh
@@ -0,0 +1,30 @@
+#! /bin/sh
+
+. ./tests.sh
+
+if [ "$1" = "-n" ]; then
+ NEG="$1"
+ shift
+fi
+
+OUTPUT="$1"
+shift
+
+verbose_run $VALGRIND "$DTC" -o "$OUTPUT" "$@"
+ret="$?"
+
+FAIL_IF_SIGNAL $ret
+
+if [ -n "$NEG" ]; then
+ if [ ! -e "$OUTPUT" ]; then
+ FAIL "Produced no output"
+ fi
+else
+ if [ -e "$OUTPUT" ]; then
+ FAIL "Incorrectly produced output"
+ fi
+fi
+
+rm -f "$OUTPUT"
+
+PASS
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 9a2a7d9..998c422 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -394,6 +394,18 @@ dtc_tests () {
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label5.dts
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label6.dts
+ # Check warning options
+ run_sh_test dtc-checkfails.sh address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
+ run_sh_test dtc-fails.sh -n test-warn-output.test.dtb -I dts -O dtb bad-ncells.dts
+ run_sh_test dtc-fails.sh test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
+ run_sh_test dtc-checkfails.sh always_fail -- -Walways_fail -I dts -O dtb test_tree1.dts
+ run_sh_test dtc-checkfails.sh -n always_fail -- -Walways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
+ run_sh_test dtc-fails.sh test-negation-1.test.dtb -Ealways_fail -I dts -O dtb test_tree1.dts
+ run_sh_test dtc-fails.sh -n test-negation-2.test.dtb -Ealways_fail -Eno_always_fail -I dts -O dtb test_tree1.dts
+ run_sh_test dtc-fails.sh test-negation-3.test.dtb -Ealways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
+ run_sh_test dtc-fails.sh -n test-negation-4.test.dtb -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
+ run_sh_test dtc-checkfails.sh size_cells_is_cell -- -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
+
# Check for proper behaviour reading from stdin
run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < test_tree1.dts
run_wrap_test cmp stdin_dtc_tree1.test.dtb dtc_tree1.test.dtb
--
1.7.10
More information about the devicetree-discuss
mailing list