From 2df402576afb333577647e86d024907e1ab33830 Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Wed, 27 Jun 2007 01:36:14 +0100 Subject: [PATCH 3/3] add c2xml program Adds new c2xml program which dumps out the parse tree for a given file as well formed xml. A DTD for the format is included as parse.dtd. --- Makefile | 15 +++ c2xml.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ parse.dtd | 48 +++++++++ 3 files changed, 409 insertions(+), 0 deletions(-) create mode 100644 c2xml.c create mode 100644 parse.dtd diff --git a/Makefile b/Makefile index 039fe38..67da31f 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ CFLAGS=-O -g -Wall -Wwrite-strings -fpic LDFLAGS=-g AR=ar +HAVE_LIBXML=$(shell pkg-config --exists libxml-2.0 && echo 'yes') + # # For debugging, uncomment the next one # @@ -21,8 +23,15 @@ PKGCONFIGDIR=$(LIBDIR)/pkgconfig PROGRAMS=test-lexing test-parsing obfuscate compile graph sparse test-linearize example \ test-unssa test-dissect ctags + + INST_PROGRAMS=sparse cgcc +ifeq ($(HAVE_LIBXML),yes) +PROGRAMS+=c2xml +INST_PROGRAMS+=c2xml +endif + LIB_H= token.h parse.h lib.h symbol.h scope.h expression.h target.h \ linearize.h bitmap.h ident-list.h compat.h flow.h allocate.h \ storage.h ptrlist.h dissect.h @@ -107,6 +116,12 @@ test-dissect: test-dissect.o $(LIBS) ctags: ctags.o $(LIBS) $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $< $(LIBS) +ifeq ($(HAVE_LIBXML),yes) +c2xml: c2xml.c $(LIBS) $(LIB_H) + $(CC) $(LDFLAGS) `pkg-config --cflags --libs libxml-2.0` -o $@ $< $(LIBS) + +endif + $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(AR) rcs $@ $(LIB_OBJS) diff --git a/c2xml.c b/c2xml.c new file mode 100644 index 0000000..e42dc31 --- /dev/null +++ b/c2xml.c @@ -0,0 +1,346 @@ +/* + * Sparse c2xml + * + * Dumps the parse tree as an xml document + * + * Copyright (C) 2007 Rob Taylor + * + * Licensed under the Open Software License version 1.1 + */ +#include +#include +#include +#include +#include +#include +#include + +#include "parse.h" +#include "scope.h" + +xmlDocPtr doc = NULL; /* document pointer */ +xmlNodePtr root_node = NULL;/* root node pointer */ +xmlDtdPtr dtd = NULL; /* DTD pointer */ +xmlNsPtr ns = NULL; /* namespace pointer */ +int idcount = 0; + +static struct symbol_list *taglist = NULL; + +static void examine_symbol(struct symbol *sym, xmlNodePtr node); + +static inline xmlNodePtr new_sym_node(struct symbol *sym, const char *name, xmlNodePtr parent) +{ + xmlNodePtr node; + char buf[256]; + const char *ident = show_ident(sym->ident); + + node = xmlNewChild(parent, NULL, "symbol", NULL); + + xmlNewProp(node, BAD_CAST "type", (xmlChar*) name); + + snprintf(buf, 256, "_%d", idcount); + xmlNewProp(node, BAD_CAST "id", BAD_CAST buf); + + if (sym->ident && ident) + xmlNewProp(node, BAD_CAST "ident", BAD_CAST ident); + xmlNewProp(node, BAD_CAST "file", BAD_CAST stream_name(sym->pos.stream)); + snprintf(buf, 256, "%d:%d", sym->pos.line, sym->pos.pos); + xmlNewProp(node, BAD_CAST "start", BAD_CAST buf); + + if (sym->endpos.type) { + snprintf(buf, 256, "%d:%d", sym->endpos.line, sym->endpos.pos); + xmlNewProp(node, BAD_CAST "end", BAD_CAST buf); + } + sym->aux = node; + + idcount++; + + return node; +} + +static inline void examine_members(struct symbol_list *list, xmlNodePtr node) +{ + struct symbol *sym; + xmlNodePtr child; + char buf[256]; + + FOR_EACH_PTR(list, sym) { + examine_symbol(sym, node); + } END_FOR_EACH_PTR(sym); +} + +static const char* get_type_name(enum type type) +{ + switch (type) { + case SYM_NODE: + return "node"; + case SYM_STRUCT: + return "struct"; + case SYM_UNION: + return "union"; + case SYM_ENUM: + return "enum"; + case SYM_PTR: + return "pointer"; + case SYM_TYPEDEF: + return "typedef"; + case SYM_TYPEOF: + return "typeof"; + case SYM_BITFIELD: + return "bitfield"; + case SYM_FN: + return "function"; + case SYM_ARRAY: + return "array"; + case SYM_BASETYPE: + return "basetype"; + case SYM_KEYWORD: + return "keyword"; + case SYM_PREPROCESSOR: + return "preprocessor"; + case SYM_UNINITIALIZED: + return "uninitialized"; + default: + die("unknown type:%d\n", type); + } +} + +static void examine_modifiers(struct symbol *sym, xmlNodePtr node) +{ + const char *modifiers[] = { + "auto", + "register", + "static", + "extern", + "const", + "volatile", + "signed", + "unsigned", + "char", + "short", + "long", + "long-long", + "typedef", + NULL, + NULL, + NULL, + NULL, + NULL, + "inline", + "addressable", + "nocast", + "noderef", + "accessed", + "toplevel", + "label", + "assigned", + "type-type", + "safe", + "user-type", + "force", + "explicitly-signed", + "bitwise"}; + + int i; + + if (sym->namespace != NS_SYMBOL) + return; + + /*iterate over the 32 bit bitfield*/ + for (i=0; i < 32; i++) { + if ((sym->ctype.modifiers & 1<bit_size); + xmlNewProp(node, BAD_CAST "bit-size", BAD_CAST buf); + snprintf(buf, 256, "%d", sym->ctype.alignment); + xmlNewProp(node, BAD_CAST "alignment", BAD_CAST buf); + snprintf(buf, 256, "%d", sym->offset); + xmlNewProp(node, BAD_CAST "offset", BAD_CAST buf); + if (is_bitfield_type(sym)) { + snprintf(buf, 256, "%d", sym->bit_offset); + xmlNewProp(node, BAD_CAST "bit-offset", BAD_CAST buf); + } +} + +static void examine_symbol(struct symbol *sym, xmlNodePtr node) +{ + xmlNodePtr child = NULL; + const char *base; + int array_size; + char buf[256]; + + if (!sym) + return; + if (sym->aux) /*already visited */ + return; + + if (sym->ident && sym->ident->reserved) + return; + + child = new_sym_node(sym, get_type_name(sym->type), node); + examine_modifiers(sym, child); + examine_layout(sym, child); + + if (sym->ctype.base_type) { + if ((base = builtin_typename(sym->ctype.base_type)) == NULL) { + if (!sym->ctype.base_type->aux) { + examine_symbol(sym->ctype.base_type, root_node); + } + xmlNewProp(child, BAD_CAST "base-type", + xmlGetProp((xmlNodePtr)sym->ctype.base_type->aux, "id")); + } else { + xmlNewProp(child, BAD_CAST "base-type-builtin", base); + } + } + if (sym->array_size) { + /* TODO: modify get_expression_value to give error return */ + array_size = get_expression_value(sym->array_size); + snprintf(buf, 256, "%d", array_size); + xmlNewProp(child, BAD_CAST "array-size", BAD_CAST buf); + } + + + switch (sym->type) { + case SYM_STRUCT: + case SYM_UNION: + examine_members(sym->symbol_list, child); + break; + case SYM_FN: + examine_members(sym->arguments, child); + break; + case SYM_UNINITIALIZED: + xmlNewProp(child, BAD_CAST "base-type-builtin", builtin_typename(sym)); + break; + } + return; +} + +static struct position *get_expansion_end (struct token *token) +{ + struct token *p1, *p2; + + for (p1=NULL, p2=NULL; + !eof_token(token); + p2 = p1, p1 = token, token = token->next); + + if (p2) + return &(p2->pos); + else + return NULL; +} + +static void examine_macro(struct symbol *sym, xmlNodePtr node) +{ + xmlNodePtr child; + struct position *pos; + char buf[256]; + + child = new_sym_node(sym, "macro", node); + pos = get_expansion_end(sym->expansion); + if (pos) { + snprintf(buf, 256, "%d:%d", pos->line, pos->pos); + xmlNewProp(child, BAD_CAST "end", BAD_CAST buf); + } else { + xmlNewProp(child, BAD_CAST "end", + xmlGetProp(child, "start")); + } +} + +static void examine_namespace(struct symbol *sym) +{ + xmlChar *namespace_type = NULL; + + if (sym->ident && sym->ident->reserved) + return; + + switch(sym->namespace) { + case NS_MACRO: + examine_macro(sym, root_node); + break; + case NS_TYPEDEF: + case NS_STRUCT: + case NS_SYMBOL: + examine_symbol(sym, root_node); + break; + case NS_NONE: + case NS_LABEL: + case NS_ITERATOR: + case NS_UNDEF: + case NS_PREPROCESSOR: + case NS_KEYWORD: + break; + default: + die("Unregonised namespace type %d",sym->namespace); + } + +} + +static int get_stream_id (const char *name) +{ + int i; + for (i=0; ipos.stream == stream_id) + examine_namespace(sym); + } END_FOR_EACH_PTR(sym); +} + +int main(int argc, char **argv) +{ + struct string_list *filelist = NULL; + struct symbol_list *symlist = NULL; + char *file; + + doc = xmlNewDoc(BAD_CAST "1.0"); + root_node = xmlNewNode(NULL, BAD_CAST "parse"); + xmlDocSetRootElement(doc, root_node); + +/* - A DTD is probably unnecessary for something like this + + dtd = xmlCreateIntSubset(doc, BAD_CAST "parse", "http://www.kernel.org/pub/software/devel/sparse/parse.dtd" NULL, BAD_CAST "parse.dtd"); + + ns = xmlNewNs (root_node, "http://www.kernel.org/pub/software/devel/sparse/parse.dtd", NULL); + + xmlSetNs(root_node, ns); +*/ + symlist = sparse_initialize(argc, argv, &filelist); + + FOR_EACH_PTR_NOTAG(filelist, file) { + examine_symbol_list(file, symlist); + sparse_keep_tokens(file); + examine_symbol_list(file, file_scope->symbols); + examine_symbol_list(file, global_scope->symbols); + } END_FOR_EACH_PTR_NOTAG(file); + + + xmlSaveFormatFileEnc("-", doc, "UTF-8", 1); + xmlFreeDoc(doc); + xmlCleanupParser(); + + return 0; +} + +/* vim:set sw=8 noet */ diff --git a/parse.dtd b/parse.dtd new file mode 100644 index 0000000..dfcef0c --- /dev/null +++ b/parse.dtd @@ -0,0 +1,48 @@ + + + + + -- 1.5.2-rc3.GIT