freedreno/decode: try harder to not crash in disasm
[mesa.git] / src / freedreno / rnn / rnn.c
index 3027288b74e4b7d8c9a9e965c7480921917f3960..d82d2a561b02bee61e86f9d519dd0fc9417dec70 100644 (file)
@@ -26,6 +26,9 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/* workaround libxml2 silliness: */
+#pragma GCC diagnostic ignored "-Wpointer-sign"
+
 #include <libxml/xmlversion.h>
 #include <libxml/parser.h>
 #include <libxml/xpath.h>
 #include <ctype.h>
 #include <stdio.h>
 #include "rnn.h"
-#include "rnn_path.h"
 #include "util.h"
 
+#include "util/u_debug.h"
+
 static char *catstr (char *a, char *b) {
        if (!a)
                return b;
@@ -53,6 +57,17 @@ static int strdiff (const char *a, const char *b) {
        return strcmp (a, b);
 }
 
+static void rnn_err(struct rnndb *db, const char *format, ...) _util_printf_format(2, 3);
+
+static void rnn_err(struct rnndb *db, const char *format, ...)
+{
+       va_list ap;
+       va_start(ap, format);
+       vfprintf(stderr, format, ap);
+       va_end(ap);
+       db->estatus = 1;
+}
+
 void rnn_init(void) {
        LIBXML_TEST_VERSION
        xmlInitParser();
@@ -97,8 +112,7 @@ static char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
        xmlNode *chain = attr->children;
        while (chain) {
                if (chain->type != XML_TEXT_NODE) {
-                       fprintf (stderr, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
                } else {
                        return chain->content;
                }
@@ -109,12 +123,11 @@ static char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
 
 static int getboolattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
        char *c = getattrib(db, file, line, attr);
-       if (!strcmp(c, "yes") || !strcmp(c, "1"))
+       if (!strcmp(c, "yes") || !strcmp(c, "1") || !strcmp(c, "true"))
                return 1;
-       if (!strcmp(c, "no") || !strcmp(c, "0"))
+       if (!strcmp(c, "no") || !strcmp(c, "0") || !strcmp(c, "false"))
                return 0;
-       fprintf (stderr, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
-       db->estatus = 1;
+       rnn_err(db, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
        return 0;
 }
 
@@ -127,8 +140,7 @@ static uint64_t getnum(struct rnndb *db, char *file, int line, xmlAttr *attr, ch
        else
                res = strtoull(c, &cc, 10);
        if (*cc)  {
-               fprintf (stderr, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
        }
        return res;
 }
@@ -200,6 +212,7 @@ static int trytypeattr (struct rnndb *db, char *file, xmlNode *node, xmlAttr *at
                return 1;
        } else if (!strcmp(attr->name, "addvariant")) {
                ti->addvariant = getboolattrib(db, file, node->line, attr);
+               return 1;
        }
        return 0;
 }
@@ -219,8 +232,7 @@ static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node)
                } else if (!strcmp(attr->name, "variants")) {
                        val->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
                } else {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
@@ -228,14 +240,12 @@ static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node)
        while (chain) {
                if (chain->type != XML_ELEMENT_NODE) {
                } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
                }
                chain = chain->next;
        }
        if (!val->name) {
-               fprintf (stderr, "%s:%d: nameless value\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless value\n", file, node->line);
                return 0;
        } else {
                return val;
@@ -251,20 +261,17 @@ static void parsespectype(struct rnndb *db, char *file, xmlNode *node) {
                if (!strcmp(attr->name, "name")) {
                        res->name = strdup(getattrib(db, file, node->line, attr));
                } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
        if (!res->name) {
-               fprintf (stderr, "%s:%d: nameless spectype\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless spectype\n", file, node->line);
                return;
        }
        for (i = 0; i < db->spectypesnum; i++)
                if (!strcmp(db->spectypes[i]->name, res->name)) {
-                       fprintf (stderr, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
                        return;
                }
        ADDARRAY(db->spectypes, res);
@@ -272,8 +279,7 @@ static void parsespectype(struct rnndb *db, char *file, xmlNode *node) {
        while (chain) {
                if (chain->type != XML_ELEMENT_NODE) {
                } else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
                }
                chain = chain->next;
        }
@@ -302,14 +308,12 @@ static void parseenum(struct rnndb *db, char *file, xmlNode *node) {
                } else if (!strcmp(attr->name, "variants")) {
                        variantsstr = strdup(getattrib(db, file, node->line, attr));
                } else {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
        if (!name) {
-               fprintf (stderr, "%s:%d: nameless enum\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless enum\n", file, node->line);
                return;
        }
        struct rnnenum *cur = 0;
@@ -323,8 +327,7 @@ static void parseenum(struct rnndb *db, char *file, xmlNode *node) {
                                strdiff(cur->varinfo.varsetstr, varsetstr) ||
                                strdiff(cur->varinfo.variantsstr, variantsstr) ||
                                cur->isinline != isinline || cur->bare != bare) {
-                       fprintf (stderr, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
                }
        } else {
                cur = calloc(sizeof *cur, 1);
@@ -345,8 +348,7 @@ static void parseenum(struct rnndb *db, char *file, xmlNode *node) {
                        if (val)
                                ADDARRAY(cur->vals, val);
                } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
                }
                chain = chain->next;
        }
@@ -365,8 +367,7 @@ static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *
                } else if (!strcmp(attr->name, "variants")) {
                        bf->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr));
                } else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
@@ -374,18 +375,15 @@ static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *
        while (chain) {
                if (chain->type != XML_ELEMENT_NODE) {
                } else if (!trytypetag(db, file, chain, &bf->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
                }
                chain = chain->next;
        }
        if (!bf->name) {
-               fprintf (stderr, "%s:%d: nameless bitfield\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless bitfield\n", file, node->line);
                return 0;
        } else if (bf->typeinfo.low < 0|| bf->typeinfo.high < 0 || bf->typeinfo.high < bf->typeinfo.low) {
-               fprintf (stderr, "%s:%d: bitfield has wrong placement\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: bitfield has wrong placement\n", file, node->line);
                return 0;
        } else {
                return bf;
@@ -415,14 +413,12 @@ static void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
                } else if (!strcmp(attr->name, "variants")) {
                        variantsstr = strdup(getattrib(db, file, node->line, attr));
                } else {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
        if (!name) {
-               fprintf (stderr, "%s:%d: nameless bitset\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless bitset\n", file, node->line);
                return;
        }
        struct rnnbitset *cur = 0;
@@ -436,8 +432,7 @@ static void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
                                strdiff(cur->varinfo.varsetstr, varsetstr) ||
                                strdiff(cur->varinfo.variantsstr, variantsstr) ||
                                cur->isinline != isinline || cur->bare != bare) {
-                       fprintf (stderr, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
                }
        } else {
                cur = calloc(sizeof *cur, 1);
@@ -458,8 +453,7 @@ static void parsebitset(struct rnndb *db, char *file, xmlNode *node) {
                        if (bf)
                                ADDARRAY(cur->bitfields, bf);
                } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
                }
                chain = chain->next;
        }
@@ -472,22 +466,22 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
                res->type = RNN_ETYPE_USE_GROUP;
                xmlAttr *attr = node->properties;
                while (attr) {
-                       if (!strcmp(attr->name, "name")) {
+                       if (!strcmp(attr->name, "ref")) {
                                res->name = strdup(getattrib(db, file, node->line, attr));
                        } else {
-                               fprintf (stderr, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
-                               db->estatus = 1;
+                               rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
                        }
                        attr = attr->next;
                }
                if (!res->name) {
-                       fprintf (stderr, "%s:%d: nameless use-group\n", file, node->line);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: nameless use-group\n", file, node->line);
                        return 0;
                }
                return res;
        } else if (!strcmp(node->name, "stripe") || !strcmp(node->name, "array")) {
                struct rnndelem *res = calloc(sizeof *res, 1);
+               if (!strcmp(node->name, "array"))
+                       res->name = "";
                res->type = (strcmp(node->name, "stripe")?RNN_ETYPE_ARRAY:RNN_ETYPE_STRIPE);
                res->length = 1;
                res->file = file;
@@ -537,12 +531,10 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
                                const char *enumname = getattrib(db, file, node->line, attr);
                                res->index = rnn_findenum(db, enumname);
                                if (!res->index) {
-                                       fprintf(stderr, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
-                                       db->estatus = 1;
+                                       rnn_err(db, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname);
                                }
                        } else {
-                               fprintf (stderr, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
-                               db->estatus = 1;
+                               rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
                        }
                        attr = attr->next;
                }
@@ -553,8 +545,7 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
                        } else if ((delem = trydelem(db, file, chain))) {
                                ADDARRAY(res->subelems, delem);
                        } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                               fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
-                               db->estatus = 1;
+                               rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
                        }
                        chain = chain->next;
                }
@@ -611,8 +602,7 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
                        else
                                fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str);
                } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
@@ -620,14 +610,12 @@ static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) {
        while (chain) {
                if (chain->type != XML_ELEMENT_NODE) {
                } else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
                }
                chain = chain->next;
        }
        if (!res->name) {
-               fprintf (stderr, "%s:%d: nameless register\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless register\n", file, node->line);
                return 0;
        } else {
        }
@@ -642,14 +630,12 @@ static void parsegroup(struct rnndb *db, char *file, xmlNode *node) {
                if (!strcmp(attr->name, "name")) {
                        name = getattrib(db, file, node->line, attr);
                } else {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
        if (!name) {
-               fprintf (stderr, "%s:%d: nameless group\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless group\n", file, node->line);
                return;
        }
        struct rnngroup *cur = 0;
@@ -670,8 +656,7 @@ static void parsegroup(struct rnndb *db, char *file, xmlNode *node) {
                } else if ((delem = trydelem(db, file, chain))) {
                        ADDARRAY(cur->subelems, delem);
                } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
                }
                chain = chain->next;
        }
@@ -702,14 +687,12 @@ static void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
                } else if (!strcmp(attr->name, "variants")) {
                        variantsstr = strdup(getattrib(db, file, node->line, attr));
                } else {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
        if (!name) {
-               fprintf (stderr, "%s:%d: nameless domain\n", file, node->line);
-               db->estatus = 1;
+               rnn_err(db, "%s:%d: nameless domain\n", file, node->line);
                return;
        }
        struct rnndomain *cur = 0;
@@ -725,8 +708,7 @@ static void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
                                cur->width != width ||
                                cur->bare != bare ||
                                (size && cur->size && size != cur->size)) {
-                       fprintf (stderr, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
                } else {
                        if (size)
                                cur->size = size;
@@ -750,8 +732,7 @@ static void parsedomain(struct rnndb *db, char *file, xmlNode *node) {
                } else if ((delem = trydelem(db, file, chain))) {
                        ADDARRAY(cur->subelems, delem);
                } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) {
-                       fprintf (stderr, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
                }
                chain = chain->next;
        }
@@ -766,8 +747,7 @@ static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
                        if(!copyright->firstyear || firstyear < copyright->firstyear)
                                copyright->firstyear = firstyear;
                } else {
-                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
                }
                attr = attr->next;
        }
@@ -793,8 +773,7 @@ static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
                                else if (!strcmp(authorattr->name, "email"))
                                        author->email = strdup(getattrib(db, file, chain->line, authorattr));
                                else {
-                                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
-                                       db->estatus = 1;
+                                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
                                }
                                authorattr = authorattr->next;
                        }
@@ -807,26 +786,22 @@ static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) {
                                                if (!strcmp(nickattr->name, "name"))
                                                        nickname = strdup(getattrib(db, file, authorchild->line, nickattr));
                                                else {
-                                                       fprintf (stderr, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
-                                                       db->estatus = 1;
+                                                       rnn_err(db, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
                                                }
                                                nickattr = nickattr->next;
                                        }
                                        if(!nickname) {
-                                               fprintf (stderr, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
-                                               db->estatus = 1;
+                                               rnn_err(db, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
                                        } else
                                                ADDARRAY(author->nicknames, nickname);
                                } else {
-                                       fprintf (stderr, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
-                                       db->estatus = 1;
+                                       rnn_err(db, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
                                }
                                authorchild = authorchild->next;
                        }
                        ADDARRAY(copyright->authors, author);
                } else {
-                       fprintf (stderr, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
                }
                chain = chain->next;
        }
@@ -855,14 +830,12 @@ static int trytop (struct rnndb *db, char *file, xmlNode *node) {
                        if (!strcmp(attr->name, "file")) {
                                subfile = getattrib(db, file, node->line, attr);
                        } else {
-                               fprintf (stderr, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
-                               db->estatus = 1;
+                               rnn_err(db, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
                        }
                        attr = attr->next;
                }
                if (!subfile) {
-                       fprintf (stderr, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
                } else {
                        rnn_parsefile(db, subfile);
                }
@@ -874,10 +847,10 @@ static int trytop (struct rnndb *db, char *file, xmlNode *node) {
        return 0;
 }
 
-void rnn_parsefile (struct rnndb *db, char *file_orig) {
-       int i;
-       char *fname;
+static char * find_file(const char *file_orig)
+{
        const char *rnn_path = getenv("RNN_PATH");
+       char *fname;
 
        if (!rnn_path)
                rnn_path = RNN_DEF_PATH;
@@ -885,10 +858,70 @@ void rnn_parsefile (struct rnndb *db, char *file_orig) {
        FILE *file = find_in_path(file_orig, rnn_path, &fname);
        if (!file) {
                fprintf (stderr, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", file_orig);
+               return NULL;
+       }
+       fclose(file);
+
+       return fname;
+}
+
+static int validate_doc(struct rnndb *db, xmlDocPtr doc, xmlNodePtr database)
+{
+       /* find the schemaLocation property: */
+       xmlAttrPtr attr = database->properties;
+       const char *schema_name = NULL;
+       char *schema_path;
+
+       while (attr) {
+               if (!strcmp(attr->name, "schemaLocation")) {
+                       xmlNodePtr data = attr->children;
+                       schema_name = data->content;
+                       /* we expect this to look like <namespace url> schema.xsd.. I think
+                        * technically it is supposed to be just a URL, but that doesn't
+                        * quite match up to what we do.. Just skip over everything up to
+                        * and including the first whitespace character:
+                        */
+                       while (schema_name && (schema_name[0] != ' '))
+                               schema_name++;
+                       schema_name++;
+                       break;
+               }
+       }
+
+       if (!schema_name) {
+               rnn_err(db, "could not find schema.  Missing schemaLocation?");
+               return 0;
+       }
+
+       schema_path = find_file(schema_name);
+       if (!schema_path) {
+               rnn_err(db, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", schema_name);
+               return 0;
+       }
+
+       xmlSchemaParserCtxtPtr parser = xmlSchemaNewParserCtxt(schema_path);
+       xmlSchemaPtr schema = xmlSchemaParse(parser);
+       xmlSchemaValidCtxtPtr validCtxt = xmlSchemaNewValidCtxt(schema);
+       int ret = xmlSchemaValidateDoc(validCtxt, doc);
+
+       xmlSchemaFreeValidCtxt(validCtxt);
+       xmlSchemaFree(schema);
+       xmlSchemaFreeParserCtxt(parser);
+
+       free(schema_path);
+
+       return ret;
+}
+
+void rnn_parsefile (struct rnndb *db, char *file_orig) {
+       int i;
+       char *fname;
+
+       fname = find_file(file_orig);
+       if (!fname) {
                db->estatus = 1;
                return;
        }
-       fclose(file);
 
        for (i = 0; i < db->filesnum; i++)
                if (!strcmp(db->files[i], fname))
@@ -897,23 +930,24 @@ void rnn_parsefile (struct rnndb *db, char *file_orig) {
        ADDARRAY(db->files, fname);
        xmlDocPtr doc = xmlParseFile(fname);
        if (!doc) {
-               fprintf (stderr, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
-               db->estatus = 1;
+               rnn_err(db, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
                return;
        }
        xmlNode *root = doc->children;
        while (root) {
                if (root->type != XML_ELEMENT_NODE) {
                } else if (strcmp(root->name, "database")) {
-                       fprintf (stderr, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
                } else {
                        xmlNode *chain = root->children;
+                       if (validate_doc(db, doc, root)) {
+                               rnn_err(db, "%s: database file has errors\n", fname);
+                               return;
+                       }
                        while (chain) {
                                if (chain->type != XML_ELEMENT_NODE) {
                                } else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) {
-                                       fprintf (stderr, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
-                                       db->estatus = 1;
+                                       rnn_err(db, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
                                }
                                chain = chain->next;
                        }
@@ -998,8 +1032,7 @@ static int findvidx (struct rnndb *db, struct rnnenum *en, char *name) {
        for (i = 0; i < en->valsnum; i++)
                if (!strcmp(en->vals[i]->name, name))
                        return i;
-       fprintf (stderr, "Cannot find variant %s in enum %s!\n", name, en->name);
-       db->estatus = 1;
+       rnn_err(db, "Cannot find variant %s in enum %s!\n", name, en->name);
        return -1;
 }
 
@@ -1024,8 +1057,7 @@ static void prepvarinfo (struct rnndb *db, char *what, struct rnnvarinfo *vi, st
        if (vi->variantsstr) {
                char *vars = vi->variantsstr;
                if (!varset) {
-                       fprintf (stderr, "%s: tried to use variants without active varset!\n", what);
-                       db->estatus = 1;
+                       rnn_err(db, "%s: tried to use variants without active varset!\n", what);
                        return;
                }
                struct rnnvarset *vs = 0;
@@ -1174,8 +1206,7 @@ static void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix,
                        ti->type = RNN_TTYPE_HEX;
                } else {
                        ti->type = RNN_TTYPE_HEX;
-                       fprintf (stderr, "%s: unknown type %s\n", prefix, ti->name);
-                       db->estatus = 1;
+                       rnn_err(db, "%s: unknown type %s\n", prefix, ti->name);
                }
        } else if (ti->bitfieldsnum) {
                ti->name = "bitfield";
@@ -1191,8 +1222,7 @@ static void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix,
                ti->type = RNN_TTYPE_HEX;
        }
        if (ti->addvariant && ti->type != RNN_TTYPE_ENUM) {
-               fprintf (stderr, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name);
-               db->estatus = 1;
+               rnn_err(db, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name);
        }
        for (i = 0; i < ti->bitfieldsnum; i++)
                prepbitfield(db,  ti->bitfields[i], prefix, vi);
@@ -1223,8 +1253,7 @@ static void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, str
                        for (i = 0; i < gr->subelemsnum; i++)
                                ADDARRAY(elem->subelems, copydelem(gr->subelems[i], elem->file));
                } else {
-                       fprintf (stderr, "group %s not found!\n", elem->name);
-                       db->estatus = 1;
+                       rnn_err(db, "group %s not found!\n", elem->name);
                }
                elem->type = RNN_ETYPE_STRIPE;
                elem->length = 1;
@@ -1237,8 +1266,7 @@ static void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, str
                return;
        if (elem->length != 1 && !elem->stride) {
                if (elem->type != RNN_ETYPE_REG) {
-                       fprintf (stderr, "%s has non-1 length, but no stride!\n", elem->fullname);
-                       db->estatus = 1;
+                       rnn_err(db, "%s has non-1 length, but no stride!\n", elem->fullname);
                } else {
                        elem->stride = elem->width/width;
                }