From 67905e421502703d87176702b4844f70fd60ded4 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 24 Feb 2011 13:30:57 -0500 Subject: [PATCH] Add AST visitors: parent links creation and semantic validator Signed-off-by: Mathieu Desnoyers --- formats/ctf/metadata/Makefile.am | 2 + formats/ctf/metadata/ctf-ast.h | 7 +- formats/ctf/metadata/ctf-parser-test.c | 16 +- .../ctf/metadata/ctf-visitor-parent-links.c | 423 +++++++++ .../metadata/ctf-visitor-semantic-validator.c | 868 ++++++++++++++++++ formats/ctf/metadata/ctf-visitor-xml.c | 6 +- 6 files changed, 1316 insertions(+), 6 deletions(-) create mode 100644 formats/ctf/metadata/ctf-visitor-parent-links.c create mode 100644 formats/ctf/metadata/ctf-visitor-semantic-validator.c diff --git a/formats/ctf/metadata/Makefile.am b/formats/ctf/metadata/Makefile.am index a75e10c6..00b12d27 100644 --- a/formats/ctf/metadata/Makefile.am +++ b/formats/ctf/metadata/Makefile.am @@ -9,4 +9,6 @@ libctf_parser_a_SOURCES = ctf-lexer.l ctf-parser.y bin_PROGRAMS = ctf-parser-test ctf_parser_test_SOURCES = \ ctf-parser-test.c ctf-visitor-xml.c \ + ctf-visitor-parent-links.c \ + ctf-visitor-semantic-validator.c \ ctf-lexer.l ctf-parser.y diff --git a/formats/ctf/metadata/ctf-ast.h b/formats/ctf/metadata/ctf-ast.h index 54ad14d5..540195a3 100644 --- a/formats/ctf/metadata/ctf-ast.h +++ b/formats/ctf/metadata/ctf-ast.h @@ -194,7 +194,10 @@ struct ctf_node { } string; struct { char *id; - /* range list or single value node */ + /* + * Range list or single value node. Contains unary + * expressions. + */ struct cds_list_head values; } enumerator; struct { @@ -227,5 +230,7 @@ struct ctf_ast { }; int ctf_visitor_print_xml(FILE *fd, int depth, struct ctf_node *node); +int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node); +int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node); #endif /* _CTF_PARSER_H */ diff --git a/formats/ctf/metadata/ctf-parser-test.c b/formats/ctf/metadata/ctf-parser-test.c index cfd847d0..9f481743 100644 --- a/formats/ctf/metadata/ctf-parser-test.c +++ b/formats/ctf/metadata/ctf-parser-test.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "ctf-scanner.h" #include "ctf-parser.h" #include "ctf-ast.h" @@ -34,16 +35,23 @@ int main(int argc, char **argv) scanner = ctf_scanner_alloc(stdin); if (!scanner) { fprintf(stderr, "Error allocating scanner\n"); - return -1; + return -ENOMEM; } ctf_scanner_append_ast(scanner); - if (ctf_visitor_print_xml(stdout, 0, &scanner->ast->root)) { + ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root); + if (ret) { fprintf(stderr, "error visiting AST for XML output\n"); - ret = -1; + goto end; } - ctf_scanner_free(scanner); + ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root); + if (ret) { + fprintf(stderr, "CTF semantic validation error %d\n", ret); + goto end; + } +end: + ctf_scanner_free(scanner); return ret; } diff --git a/formats/ctf/metadata/ctf-visitor-parent-links.c b/formats/ctf/metadata/ctf-visitor-parent-links.c new file mode 100644 index 00000000..44e20315 --- /dev/null +++ b/formats/ctf/metadata/ctf-visitor-parent-links.c @@ -0,0 +1,423 @@ +/* + * ctf-visitor-parent-links.c + * + * Common Trace Format Metadata Parent Link Creator. + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ctf-scanner.h" +#include "ctf-parser.h" +#include "ctf-ast.h" + +#define printf_dbg(fmt, args...) fprintf(fd, "%s: " fmt, __func__, ## args) + +static +int ctf_visitor_unary_expression(FILE *fd, int depth, struct ctf_node *node) +{ + int ret = 0; + + switch (node->u.unary_expression.link) { + case UNARY_LINK_UNKNOWN: + case UNARY_DOTLINK: + case UNARY_ARROWLINK: + case UNARY_DOTDOTDOT: + break; + default: + fprintf(fd, "[error] %s: unknown expression link type %d\n", __func__, + (int) node->u.unary_expression.link); + return -EINVAL; + } + + switch (node->u.unary_expression.type) { + case UNARY_STRING: + case UNARY_SIGNED_CONSTANT: + case UNARY_UNSIGNED_CONSTANT: + break; + case UNARY_SBRAC: + node->u.unary_expression.u.sbrac_exp->parent = node; + ret = ctf_visitor_unary_expression(fd, depth + 1, + node->u.unary_expression.u.sbrac_exp); + if (ret) + return ret; + break; + case UNARY_NESTED: + node->u.unary_expression.u.nested_exp->parent = node; + ret = ctf_visitor_unary_expression(fd, depth + 1, + node->u.unary_expression.u.nested_exp); + if (ret) + return ret; + break; + + case UNARY_UNKNOWN: + default: + fprintf(fd, "[error] %s: unknown expression type %d\n", __func__, + (int) node->u.unary_expression.type); + return -EINVAL; + } + return 0; +} + +static +int ctf_visitor_type_specifier(FILE *fd, int depth, struct ctf_node *node) +{ + switch (node->u.type_specifier.type) { + case TYPESPEC_VOID: + case TYPESPEC_CHAR: + case TYPESPEC_SHORT: + case TYPESPEC_INT: + case TYPESPEC_LONG: + case TYPESPEC_FLOAT: + case TYPESPEC_DOUBLE: + case TYPESPEC_SIGNED: + case TYPESPEC_UNSIGNED: + case TYPESPEC_BOOL: + case TYPESPEC_COMPLEX: + case TYPESPEC_CONST: + case TYPESPEC_ID_TYPE: + break; + + case TYPESPEC_UNKNOWN: + default: + fprintf(fd, "[error] %s: unknown type specifier %d\n", __func__, + (int) node->u.type_specifier.type); + return -EINVAL; + } + return 0; +} + +static +int ctf_visitor_type_declarator(FILE *fd, int depth, struct ctf_node *node) +{ + int ret = 0; + struct ctf_node *iter; + + depth++; + + if (!cds_list_empty(&node->u.type_declarator.pointers)) { + cds_list_for_each_entry(iter, &node->u.type_declarator.pointers, + siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + } + + switch (node->u.type_declarator.type) { + case TYPEDEC_ID: + break; + case TYPEDEC_NESTED: + if (node->u.type_declarator.u.nested.type_declarator) { + node->u.type_declarator.u.nested.type_declarator->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, + node->u.type_declarator.u.nested.type_declarator); + if (ret) + return ret; + } + if (node->u.type_declarator.u.nested.length) { + node->u.type_declarator.u.nested.length->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, + node->u.type_declarator.u.nested.length); + if (ret) + return ret; + } + if (node->u.type_declarator.bitfield_len) { + node->u.type_declarator.bitfield_len = node; + ret = ctf_visitor_parent_links(fd, depth + 1, + node->u.type_declarator.bitfield_len); + if (ret) + return ret; + } + break; + case TYPEDEC_UNKNOWN: + default: + fprintf(fd, "[error] %s: unknown type declarator %d\n", __func__, + (int) node->u.type_declarator.type); + return -EINVAL; + } + depth--; + return 0; +} + +int ctf_visitor_parent_links(FILE *fd, int depth, struct ctf_node *node) +{ + int ret = 0; + struct ctf_node *iter; + + switch (node->type) { + case NODE_ROOT: + cds_list_for_each_entry(iter, &node->u.root._typedef, + siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.typealias, + siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.declaration_specifier, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.trace, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.stream, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.event, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_EVENT: + cds_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_STREAM: + cds_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_TRACE: + cds_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_CTF_EXPRESSION: + depth++; + cds_list_for_each_entry(iter, &node->u.ctf_expression.left, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_UNARY_EXPRESSION: + return ctf_visitor_unary_expression(fd, depth, node); + + case NODE_TYPEDEF: + depth++; + cds_list_for_each_entry(iter, &node->u._typedef.declaration_specifier, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u._typedef.type_declarators, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_TARGET: + depth++; + cds_list_for_each_entry(iter, &node->u.typealias_target.declaration_specifier, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.typealias_target.type_declarators, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_ALIAS: + depth++; + cds_list_for_each_entry(iter, &node->u.typealias_alias.declaration_specifier, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.typealias_alias.type_declarators, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS: + node->u.typealias.target->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias.target); + if (ret) + return ret; + node->u.typealias.alias->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, node->u.typealias.alias); + if (ret) + return ret; + break; + + case NODE_TYPE_SPECIFIER: + ret = ctf_visitor_type_specifier(fd, depth, node); + if (ret) + return ret; + break; + case NODE_POINTER: + break; + case NODE_TYPE_DECLARATOR: + ret = ctf_visitor_type_declarator(fd, depth, node); + if (ret) + return ret; + break; + + case NODE_FLOATING_POINT: + cds_list_for_each_entry(iter, &node->u.floating_point.expressions, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_INTEGER: + cds_list_for_each_entry(iter, &node->u.integer.expressions, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_STRING: + cds_list_for_each_entry(iter, &node->u.string.expressions, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_ENUMERATOR: + if (node->u.enumerator.id) + fprintf(fd, " id=\"%s\"", node->u.enumerator.id); + fprintf(fd, ">\n"); + cds_list_for_each_entry(iter, &node->u.enumerator.values, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_ENUM: + if (node->u._struct.name) + fprintf(fd, "\n", + node->u._enum.enum_id); + else + fprintf(fd, "\n"); + depth++; + + if (node->u._enum.container_type) { + node->u._enum.container_type->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, node->u._enum.container_type); + if (ret) + return ret; + } + + cds_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + cds_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.declaration_specifier, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.type_declarators, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_VARIANT: + if (node->u.variant.choice) + fprintf(fd, " choice=\"%s\"", node->u.variant.choice); + cds_list_for_each_entry(iter, &node->u.variant.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_STRUCT: + cds_list_for_each_entry(iter, &node->u._struct.declaration_list, siblings) { + iter->parent = node; + ret = ctf_visitor_parent_links(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_UNKNOWN: + default: + fprintf(fd, "[error] %s: unknown node type %d\n", __func__, + (int) node->type); + return -EINVAL; + } + return ret; +} diff --git a/formats/ctf/metadata/ctf-visitor-semantic-validator.c b/formats/ctf/metadata/ctf-visitor-semantic-validator.c new file mode 100644 index 00000000..c7473d67 --- /dev/null +++ b/formats/ctf/metadata/ctf-visitor-semantic-validator.c @@ -0,0 +1,868 @@ +/* + * ctf-visitor-semantic-validator.c + * + * Common Trace Format Metadata Semantic Validator. + * + * Copyright 2010 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ctf-scanner.h" +#include "ctf-parser.h" +#include "ctf-ast.h" + +#define _cds_list_first_entry(ptr, type, member) \ + cds_list_entry((ptr)->next, type, member) + +#define printf_dbg(fmt, args...) fprintf(fd, "%s: " fmt, __func__, ## args) + +static +int _ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node); + +static +int ctf_visitor_unary_expression(FILE *fd, int depth, struct ctf_node *node) +{ + struct ctf_node *iter; + int is_ctf_exp_left = 0; + + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + cds_list_for_each_entry(iter, &node->parent->u.ctf_expression.left, + siblings) { + if (iter == node) { + is_ctf_exp_left = 1; + /* + * We are a left child of a ctf expression. + * We are only allowed to be a string. + */ + if (node->u.unary_expression.type != UNARY_STRING) + goto errperm; + break; + } + } + /* Right child of a ctf expression can be any type of unary exp. */ + break; /* OK */ + case NODE_TYPE_DECLARATOR: + /* + * We are the length of a type declarator. We can only be + * a numeric constant. + */ + switch (node->u.unary_expression.type) { + case UNARY_SIGNED_CONSTANT: + case UNARY_UNSIGNED_CONSTANT: + break; + default: + goto errperm; + } + break; /* OK */ + case NODE_ENUMERATOR: + /* The enumerator parent has validated our validity already. */ + break; /* OK */ + + case NODE_UNARY_EXPRESSION: + /* + * We disallow nested unary expressions and "sbrac" unary + * expressions. + */ + goto errperm; + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_ENUM: + case NODE_STRING: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + + switch (node->u.unary_expression.link) { + case UNARY_LINK_UNKNOWN: + break; + case UNARY_DOTLINK: + case UNARY_ARROWLINK: + /* We only allow -> and . links between children of ctf_expression. */ + if (node->parent->type != NODE_CTF_EXPRESSION) + return -EPERM; + /* We don't allow link on the first node of the list */ + if (_cds_list_first_entry(is_ctf_exp_left ? + &node->parent->u.ctf_expression.left : + &node->parent->u.ctf_expression.right, + struct ctf_node, + siblings) == node) + return -EPERM; + break; + case UNARY_DOTDOTDOT: + /* We only allow ... link between children of enumerator. */ + if (node->parent->type != NODE_ENUMERATOR) + return -EPERM; + /* We don't allow link on the first node of the list */ + if (_cds_list_first_entry(&node->parent->u.enumerator.values, + struct ctf_node, + siblings) == node) + return -EPERM; + break; + default: + fprintf(fd, "[error] %s: unknown expression link type %d\n", __func__, + (int) node->u.unary_expression.link); + return -EINVAL; + } + return 0; + +errinval: + fprintf(fd, "[error] %s: incoherent parent type %d for node type %d\n", __func__, + (int) node->parent->type, (int) node->type); + return -EINVAL; /* Incoherent structure */ + +errperm: + return -EPERM; /* Structure not allowed */ +} + +static +int ctf_visitor_type_specifier(FILE *fd, int depth, struct ctf_node *node) +{ + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + case NODE_TYPE_DECLARATOR: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_ENUM: + break; /* OK */ + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + return 0; +errinval: + fprintf(fd, "[error] %s: incoherent parent type %d for node type %d\n", __func__, + (int) node->parent->type, (int) node->type); + return -EINVAL; /* Incoherent structure */ +} + +static +int ctf_visitor_type_declarator(FILE *fd, int depth, struct ctf_node *node) +{ + int ret = 0; + struct ctf_node *iter; + + depth++; + + switch (node->parent->type) { + case NODE_TYPE_DECLARATOR: + /* + * A nested type declarator is not allowed to contain pointers. + */ + if (!cds_list_empty(&node->u.type_declarator.pointers)) + goto errperm; + /* Fall-through */ + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + + if (!cds_list_empty(&node->u.type_declarator.pointers)) { + cds_list_for_each_entry(iter, &node->u.type_declarator.pointers, + siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + } + + switch (node->u.type_declarator.type) { + case TYPEDEC_ID: + break; + case TYPEDEC_NESTED: + if (node->u.type_declarator.u.nested.type_declarator) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, + node->u.type_declarator.u.nested.type_declarator); + if (ret) + return ret; + } + if (node->u.type_declarator.u.nested.length) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, + node->u.type_declarator.u.nested.length); + if (ret) + return ret; + } + if (node->u.type_declarator.bitfield_len) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, + node->u.type_declarator.bitfield_len); + if (ret) + return ret; + } + break; + case TYPEDEC_UNKNOWN: + default: + fprintf(fd, "[error] %s: unknown type declarator %d\n", __func__, + (int) node->u.type_declarator.type); + return -EINVAL; + } + depth--; + return 0; + +errinval: + fprintf(fd, "[error] %s: incoherent parent type %d for node type %d\n", __func__, + (int) node->parent->type, (int) node->type); + return -EINVAL; /* Incoherent structure */ + +errperm: + return -EPERM; /* Structure not allowed */ +} + +static +int _ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node) +{ + int ret = 0; + struct ctf_node *iter; + + switch (node->type) { + case NODE_ROOT: + cds_list_for_each_entry(iter, &node->u.root._typedef, + siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.typealias, + siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.declaration_specifier, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.trace, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.stream, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.root.event, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_EVENT: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + cds_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_STREAM: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + cds_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_TRACE: + switch (node->parent->type) { + case NODE_ROOT: + break; /* OK */ + default: + goto errinval; + } + + cds_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_CTF_EXPRESSION: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + } + + depth++; + cds_list_for_each_entry(iter, &node->u.ctf_expression.left, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_UNARY_EXPRESSION: + return ctf_visitor_unary_expression(fd, depth, node); + + case NODE_TYPEDEF: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_VARIANT: + case NODE_STRUCT: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + default: + goto errinval; + } + + depth++; + cds_list_for_each_entry(iter, &node->u._typedef.declaration_specifier, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u._typedef.type_declarators, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_TARGET: + switch (node->parent->type) { + case NODE_TYPEALIAS: + break; /* OK */ + default: + goto errinval; + } + + depth++; + cds_list_for_each_entry(iter, &node->u.typealias_target.declaration_specifier, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.typealias_target.type_declarators, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS_ALIAS: + switch (node->parent->type) { + case NODE_TYPEALIAS: + break; /* OK */ + default: + goto errinval; + } + + depth++; + cds_list_for_each_entry(iter, &node->u.typealias_alias.declaration_specifier, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.typealias_alias.type_declarators, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_TYPEALIAS: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_VARIANT: + case NODE_STRUCT: + break; /* OK */ + + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + default: + goto errinval; + } + + ret = _ctf_visitor_semantic_check(fd, depth + 1, node->u.typealias.target); + if (ret) + return ret; + ret = _ctf_visitor_semantic_check(fd, depth + 1, node->u.typealias.alias); + if (ret) + return ret; + break; + + case NODE_TYPE_SPECIFIER: + ret = ctf_visitor_type_specifier(fd, depth, node); + if (ret) + return ret; + break; + case NODE_POINTER: + switch (node->parent->type) { + case NODE_TYPE_DECLARATOR: + break; /* OK */ + default: + goto errinval; + } + break; + case NODE_TYPE_DECLARATOR: + ret = ctf_visitor_type_declarator(fd, depth, node); + if (ret) + return ret; + break; + + case NODE_FLOATING_POINT: + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + cds_list_for_each_entry(iter, &node->u.floating_point.expressions, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_INTEGER: + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + case NODE_UNARY_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPE_DECLARATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + + } + + cds_list_for_each_entry(iter, &node->u.integer.expressions, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_STRING: + switch (node->parent->type) { + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + + cds_list_for_each_entry(iter, &node->u.string.expressions, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_ENUMERATOR: + switch (node->parent->type) { + case NODE_ENUM: + break; + default: + goto errinval; + } + /* + * Enumerators are only allows to contain: + * numeric unary expression + * or num. unary exp. ... num. unary exp + */ + { + int count = 0; + + cds_list_for_each_entry(iter, &node->parent->u.enumerator.values, + siblings) { + switch (count++) { + case 0: if (iter->type != NODE_UNARY_EXPRESSION + || (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT + && iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) + || iter->u.unary_expression.link != UNARY_LINK_UNKNOWN) + goto errperm; + break; + case 1: if (iter->type != NODE_UNARY_EXPRESSION + || (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT + && iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) + || iter->u.unary_expression.link != UNARY_DOTDOTDOT) + goto errperm; + break; + default: + goto errperm; + } + } + } + + cds_list_for_each_entry(iter, &node->u.enumerator.values, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_ENUM: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPE_DECLARATOR: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + + depth++; + if (node->u._enum.container_type) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, node->u._enum.container_type); + if (ret) + return ret; + } + + cds_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + depth--; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + switch (node->parent->type) { + case NODE_STRUCT: + case NODE_VARIANT: + break; + default: + goto errinval; + } + cds_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.declaration_specifier, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + cds_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.type_declarators, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + case NODE_VARIANT: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + cds_list_for_each_entry(iter, &node->u.variant.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_STRUCT: + switch (node->parent->type) { + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_TRACE: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + break; /* OK */ + + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + default: + goto errinval; + + case NODE_UNARY_EXPRESSION: + goto errperm; + } + cds_list_for_each_entry(iter, &node->u._struct.declaration_list, siblings) { + ret = _ctf_visitor_semantic_check(fd, depth + 1, iter); + if (ret) + return ret; + } + break; + + case NODE_UNKNOWN: + default: + fprintf(fd, "[error] %s: unknown node type %d\n", __func__, + (int) node->type); + return -EINVAL; + } + return ret; + +errinval: + fprintf(fd, "[error] %s: incoherent parent type %d for node type %d\n", __func__, + (int) node->parent->type, (int) node->type); + return -EINVAL; /* Incoherent structure */ + +errperm: + return -EPERM; /* Structure not allowed */ +} + +int ctf_visitor_semantic_check(FILE *fd, int depth, struct ctf_node *node) +{ + int ret = 0; + + /* + * First make sure we create the parent links for all children. Let's + * take the safe route and recreate them at each validation, just in + * case the structure has changed. + */ + ret = ctf_visitor_parent_links(fd, depth, node); + if (ret) + return ret; + return _ctf_visitor_semantic_check(fd, depth, node); +} diff --git a/formats/ctf/metadata/ctf-visitor-xml.c b/formats/ctf/metadata/ctf-visitor-xml.c index d768b7a3..5ca93048 100644 --- a/formats/ctf/metadata/ctf-visitor-xml.c +++ b/formats/ctf/metadata/ctf-visitor-xml.c @@ -31,7 +31,8 @@ #define printf_dbg(fmt, args...) fprintf(stderr, "%s: " fmt, __func__, ## args) -static void print_tabs(FILE *fd, int depth) +static +void print_tabs(FILE *fd, int depth) { int i; @@ -39,6 +40,7 @@ static void print_tabs(FILE *fd, int depth) fprintf(fd, "\t"); } +static int ctf_visitor_print_unary_expression(FILE *fd, int depth, struct ctf_node *node) { int ret = 0; @@ -113,6 +115,7 @@ int ctf_visitor_print_unary_expression(FILE *fd, int depth, struct ctf_node *nod return 0; } +static int ctf_visitor_print_type_specifier(FILE *fd, int depth, struct ctf_node *node) { print_tabs(fd, depth); @@ -169,6 +172,7 @@ int ctf_visitor_print_type_specifier(FILE *fd, int depth, struct ctf_node *node) return 0; } +static int ctf_visitor_print_type_declarator(FILE *fd, int depth, struct ctf_node *node) { int ret = 0; -- 2.34.1