Browse Source

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
David Gibson 13 years ago committed by Jon Loeliger
parent
commit
d5399197e9
  1. 84
      checks.c
  2. 13
      dtc.c
  3. 1
      dtc.h
  4. 20
      tests/dtc-checkfails.sh
  5. 30
      tests/dtc-fails.sh
  6. 12
      tests/run_tests.sh

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

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

@ -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 */

20
tests/dtc-checkfails.sh

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

30
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

12
tests/run_tests.sh

@ -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…
Cancel
Save