Allow toggling of semantic checks
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@gibson.dropbear.id.au>main
parent
511dedd40f
commit
d5399197e9
84
checks.c
84
checks.c
|
@ -58,7 +58,7 @@ struct check {
|
||||||
struct check **prereq;
|
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##_prereqs[] = { __VA_ARGS__ }; \
|
||||||
static struct check nm = { \
|
static struct check nm = { \
|
||||||
.name = #nm, \
|
.name = #nm, \
|
||||||
|
@ -73,22 +73,30 @@ struct check {
|
||||||
.prereq = nm##_prereqs, \
|
.prereq = nm##_prereqs, \
|
||||||
};
|
};
|
||||||
#define WARNING(nm, tfn, nfn, pfn, d, ...) \
|
#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, ...) \
|
#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, ...) \
|
#define TREE_WARNING(nm, d, ...) \
|
||||||
WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
||||||
#define TREE_ERROR(nm, d, ...) \
|
#define TREE_ERROR(nm, d, ...) \
|
||||||
ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
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, ...) \
|
#define NODE_WARNING(nm, d, ...) \
|
||||||
WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
||||||
#define NODE_ERROR(nm, d, ...) \
|
#define NODE_ERROR(nm, d, ...) \
|
||||||
ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
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, ...) \
|
#define PROP_WARNING(nm, d, ...) \
|
||||||
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
||||||
#define PROP_ERROR(nm, d, ...) \
|
#define PROP_ERROR(nm, d, ...) \
|
||||||
ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
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__
|
#ifdef __GNUC__
|
||||||
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
|
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
|
||||||
|
@ -179,6 +187,13 @@ out:
|
||||||
* Utility check functions
|
* 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,
|
static void check_is_string(struct check *c, struct node *root,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
|
@ -649,8 +664,71 @@ static struct check *check_table[] = {
|
||||||
|
|
||||||
&avoid_default_addr_size,
|
&avoid_default_addr_size,
|
||||||
&obsolete_chosen_interrupt_controller,
|
&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)
|
void process_checks(int force, struct boot_info *bi)
|
||||||
{
|
{
|
||||||
struct node *dt = bi->dt;
|
struct node *dt = bi->dt;
|
||||||
|
|
13
dtc.c
13
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\tlegacy - \"linux,phandle\" properties only\n");
|
||||||
fprintf(stderr, "\t\t\tepapr - \"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\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);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +118,7 @@ int main(int argc, char *argv[])
|
||||||
minsize = 0;
|
minsize = 0;
|
||||||
padsize = 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) {
|
!= EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'I':
|
case 'I':
|
||||||
|
@ -173,6 +176,14 @@ int main(int argc, char *argv[])
|
||||||
sort = 1;
|
sort = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'W':
|
||||||
|
parse_checks_option(true, false, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
parse_checks_option(false, true, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
|
1
dtc.h
1
dtc.h
|
@ -226,6 +226,7 @@ void sort_tree(struct boot_info *bi);
|
||||||
|
|
||||||
/* Checks */
|
/* Checks */
|
||||||
|
|
||||||
|
void parse_checks_option(bool warn, bool error, const char *optarg);
|
||||||
void process_checks(int force, struct boot_info *bi);
|
void process_checks(int force, struct boot_info *bi);
|
||||||
|
|
||||||
/* Flattened trees */
|
/* Flattened trees */
|
||||||
|
|
|
@ -4,10 +4,20 @@
|
||||||
|
|
||||||
for x; do
|
for x; do
|
||||||
shift
|
shift
|
||||||
|
if [ "$x" = "-n" ]; then
|
||||||
|
for x; do
|
||||||
|
shift
|
||||||
|
if [ "$x" = "--" ]; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
NOCHECKS="$NOCHECKS $x"
|
||||||
|
done
|
||||||
|
break;
|
||||||
|
fi
|
||||||
if [ "$x" = "--" ]; then
|
if [ "$x" = "--" ]; then
|
||||||
break;
|
break;
|
||||||
fi
|
fi
|
||||||
CHECKS="$CHECKS $x"
|
YESCHECKS="$YESCHECKS $x"
|
||||||
done
|
done
|
||||||
|
|
||||||
LOG=tmp.log.$$
|
LOG=tmp.log.$$
|
||||||
|
@ -19,10 +29,16 @@ ret="$?"
|
||||||
|
|
||||||
FAIL_IF_SIGNAL $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
|
if ! grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
|
||||||
FAIL "Failed to trigger check \"$c\""
|
FAIL "Failed to trigger check \"$c\""
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for c in $NOCHECKS; do
|
||||||
|
if grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
|
||||||
|
FAIL "Incorrectly triggered check \"$c\""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
PASS
|
PASS
|
||||||
|
|
|
@ -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
|
|
@ -396,6 +396,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-label5.dts
|
||||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label6.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
|
# Check for proper behaviour reading from stdin
|
||||||
run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < test_tree1.dts
|
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
|
run_wrap_test cmp stdin_dtc_tree1.test.dtb dtc_tree1.test.dtb
|
||||||
|
|
Loading…
Reference in New Issue