From: Fabien Parent <fparent@xxxxxxxxxxxx> The verbose option '-B' will show additional messages in addition to all validation errors. Right now the level 0 prints every nodes which don't have at least one schema associated to it. Level 1 prints every properties which were not validated due to missing constraints. Activate the verbose mode by default into the Makefile. Usage example: dtc -M ./bindings -B 1 file.dts A count of errors found so far as also been added and is printed on each error. Signed-off-by: Fabien Parent <fparent@xxxxxxxxxxxx> Signed-off-by: Benoit Cousson <bcousson@xxxxxxxxxxxx> --- scripts/Makefile.lib | 2 +- scripts/dtc/dtc.c | 11 ++++- scripts/dtc/dtc.h | 1 + scripts/dtc/schema.c | 124 ++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 118 insertions(+), 20 deletions(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 358dd69..ea1484e 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -264,7 +264,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb quiet_cmd_dtc = DTC $@ cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \ - -M $(objtree)/bindings \ + -M $(objtree)/bindings -B 1 \ -i $(dir $<) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) ; \ cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index a7881f0..8fee7ca 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -99,6 +99,8 @@ static void __attribute__ ((noreturn)) usage(void) fprintf(stderr, "\t-M <schema folder>"); fprintf(stderr, "\t\tCheck the dts using schemas from the specified folder\n"); + fprintf(stderr, "\t-B <number>\n"); + fprintf(stderr, "\t\tLevel of verbosity from the schema validation\n"); exit(3); } @@ -111,7 +113,7 @@ int main(int argc, char *argv[]) const char *outname = "-"; const char *depname = NULL; const char *schemadir = NULL; - int force = 0, sort = 0; + int force = 0, sort = 0, verbose = 0; const char *arg; int opt; FILE *outf = NULL; @@ -123,7 +125,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:sW:E:M:")) + while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:M:B:")) != EOF) { switch (opt) { case 'I': @@ -192,6 +194,10 @@ int main(int argc, char *argv[]) parse_checks_option(false, true, optarg); break; + case 'B': + verbose = strtol(optarg, NULL, 0); + break; + case 'h': default: usage(); @@ -223,6 +229,7 @@ int main(int argc, char *argv[]) if (streq(inform, "dts")) { bi = dt_from_source(arg); if (schemadir) { + set_verbosity_level(verbose); sdb = build_schema_db(schemadir); validate_dt(sdb, bi); free_schema_db(sdb); diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 64fdc8a..a4731e0 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -293,6 +293,7 @@ int validate_dt(struct schema_db *db, struct boot_info *bi); struct schema_db *build_schema_db(const char *dir); void free_schema_db(struct schema_db *db); void exit_on_schema_validation_failure(int exit); +void set_verbosity_level(int verbosity); void add_to_schema_db(struct schema_db *db, const char *file); struct schema_db *new_schema_db(void); diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c index e349e01..3a2f831 100644 --- a/scripts/dtc/schema.c +++ b/scripts/dtc/schema.c @@ -46,6 +46,8 @@ static const char *const SCHEMA_EXT = ".schema"; static const char *const VALUE_PROPNAME = "value"; static int exit_on_failure = 0; +static int verbose; +static int error_count; struct str_list { char *str; @@ -57,6 +59,11 @@ struct node_list { struct node_list *next; }; +struct property_list { + struct property *property; + struct property_list *next; +}; + struct range { uint32_t low; uint32_t high; @@ -236,7 +243,7 @@ static void dt_error(struct node_list *path, assert(format); - fprintf(stderr, "FATAL ERROR"); + fprintf(stderr, "[%d] FATAL ERROR", ++error_count); if (p) { fprintf(stderr, " in %s:%d:%d", p->loc.file, p->loc.line, p->loc.col); @@ -581,15 +588,42 @@ static int check_value(struct property *p, struct prop_constraints *pc) return 1; } +static void remove_from_property_list(struct property *p, + struct property_list **plist) +{ + struct property_list *iter; + struct property_list *next_iter; + struct property_list *prev_iter = NULL; + + if (!plist || !*plist) + return; + + iter = *plist; + for_each_safe(iter, iter, next_iter) { + if (strcmp(p->name, iter->property->name)) { + prev_iter = iter; + continue; + } + + if (prev_iter) + prev_iter->next = iter->next; + else + *plist = iter->next; + free(iter); + } +} + static int validate_properties(struct node *n, struct node *schema, - struct node_list *path); + struct node_list *path, + struct property_list **plist); static int validate_property(struct node *n, struct property *p, struct prop_constraints *pc, struct node *schema, - struct node_list *path) + struct node_list *path, + struct property_list **plist) { int ret = 1; @@ -598,12 +632,16 @@ static int validate_property(struct node *n, assert(pc); assert(path); + if (p && plist) + remove_from_property_list(p, plist); + if (pc->is_required && !p) { if (pc->can_be_inherited && path->next) { assert(path->next->n); ret &= validate_properties(path->next->n, schema, - path->next); + path->next, + plist); } else { DT_ERROR(path, NULL, "Missing property '%s'\n", schema->name); @@ -636,7 +674,8 @@ end: static int validate_properties(struct node *n, struct node *schema, - struct node_list *path) + struct node_list *path, + struct property_list **plist) { struct property *p; struct property *iter; @@ -652,13 +691,13 @@ static int validate_properties(struct node *n, iter = n->proplist; p = get_property_matching_pattern(&iter, pc->name ?: schema->name); - ret &= validate_property(n, p, pc, schema, path); + ret &= validate_property(n, p, pc, schema, path, plist); /* if other properties match the pattern */ while (iter && p) { p = get_property_matching_pattern(&iter, schema->name); if (p) - ret &= validate_property(n, p, pc, schema, path); + ret &= validate_property(n, p, pc, schema, path, plist); else break; } @@ -722,12 +761,14 @@ static struct node *find_parent_node(struct node *schema, static int validate_node(struct node *n, struct node_constraints *nc, - struct node_list *path); + struct node_list *path, + struct property_list **plist); static void free_node_constraints(struct node_constraints *nc); static int validate_parents(struct node *schema, - struct node_list *path) + struct node_list *path, + struct property_list **plist) { struct node *n; struct node_constraints *nc; @@ -746,7 +787,7 @@ static int validate_parents(struct node *schema, memset(nc, 0, sizeof(*nc)); load_node_constraints(nc, schema); nc->dt = schema; - ret &= validate_node(n, nc, path); + ret &= validate_node(n, nc, path, plist); free_node_constraints(nc); } @@ -792,7 +833,8 @@ static struct node *find_current_compatible_node(struct node_constraints *nc) } static int validate_compatible(struct node_constraints *nc, - struct node_list *path) + struct node_list *path, + struct property_list **plist) { int ret = 1; struct node *n; @@ -808,12 +850,13 @@ static int validate_compatible(struct node_constraints *nc, if (!n) return ret; - return ret & validate_parents(n, path); + return ret & validate_parents(n, path, plist); } static int validate_node(struct node *n, struct node_constraints *nc, - struct node_list *path) + struct node_list *path, + struct property_list **plist) { struct node *iter; struct str_list *pattern; @@ -828,9 +871,9 @@ static int validate_node(struct node *n, for (iter = nc->dt->children; iter; iter = iter->next_sibling) { if (!strcmp(iter->name, "parents")) - ret &= validate_parents(iter, path); + ret &= validate_parents(iter, path, plist); else - ret &= validate_properties(n, iter, path); + ret &= validate_properties(n, iter, path, plist); } /* Check whether the node has all the required children nodes */ @@ -915,6 +958,25 @@ end: return ret; } +static struct property_list *build_proplist(struct node *node) +{ + struct property *p; + struct property_list *plist = NULL; + struct property_list *new_plist; + + for (p = node->proplist; p; p = p->next) { + new_plist = xmalloc(sizeof(*new_plist)); + memset(new_plist, 0, sizeof(*new_plist)); + + new_plist->next = plist; + + plist = new_plist; + plist->property = p; + } + + return plist; +} + static int for_each_compatible_validate(struct schema_db *db, struct property *p, struct node *node, @@ -924,23 +986,46 @@ static int for_each_compatible_validate(struct schema_db *db, int i; int offset = 0; int ret = 1; + int has_compatible_in_db = 0; + struct property_list *plist; + struct property_list *plist_next; + char *path_str; assert(db); assert(node); assert(p); assert(p->val.type == STRING); + plist = build_proplist(node); + while (offset >= 0 && offset < p->val.len) { i = 0; + has_compatible_in_db = 0; while ((nc = get_node_constraints_of(db, p->val.val + offset, &i)) != NULL) { - ret &= validate_node(node, nc, path); - ret &= validate_compatible(nc, path); + ret &= validate_node(node, nc, path, &plist); + ret &= validate_compatible(nc, path, &plist); + has_compatible_in_db = 1; + } + + if (!has_compatible_in_db && verbose) { + fprintf(stderr, "[%d] No schema available for '%s'\n", + ++error_count, p->val.val + offset); } offset = get_next_string_offset(p, offset); } + if (verbose > 1) { + for_each_safe(plist, plist, plist_next) { + path_str = build_path(path); + fprintf(stderr, "[%d] Property undefined: '%s%s'\n", + ++error_count, path_str, plist->property->name); + free(plist); + free(path_str); + } + } + return ret; } @@ -998,6 +1083,11 @@ void exit_on_schema_validation_failure(int exit) exit_on_failure = exit; } +void set_verbosity_level(int verbosity) +{ + verbose = verbosity; +} + /* Schema DB */ static int is_schema_file(const char *file) -- 1.8.1.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html