1 /*
   2  * Sparse c2xml
   3  *
   4  * Dumps the parse tree as an xml document
   5  *
   6  * Copyright (C) 2007 Rob Taylor
   7  *
   8  * Permission is hereby granted, free of charge, to any person obtaining a copy
   9  * of this software and associated documentation files (the "Software"), to deal
  10  * in the Software without restriction, including without limitation the rights
  11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12  * copies of the Software, and to permit persons to whom the Software is
  13  * furnished to do so, subject to the following conditions:
  14  *
  15  * The above copyright notice and this permission notice shall be included in
  16  * all copies or substantial portions of the Software.
  17  *
  18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24  * THE SOFTWARE.
  25  */
  26 #include <stdlib.h>
  27 #include <stdio.h>
  28 #include <string.h>
  29 #include <unistd.h>
  30 #include <fcntl.h>
  31 #include <assert.h>
  32 #include <libxml/parser.h>
  33 #include <libxml/tree.h>
  34 
  35 #include "expression.h"
  36 #include "parse.h"
  37 #include "scope.h"
  38 #include "symbol.h"
  39 
  40 static xmlDocPtr doc = NULL;       /* document pointer */
  41 static xmlNodePtr root_node = NULL;/* root node pointer */
  42 static int idcount = 0;
  43 
  44 static void examine_symbol(struct symbol *sym, xmlNodePtr node);
  45 
  46 static xmlAttrPtr newProp(xmlNodePtr node, const char *name, const char *value)
  47 {
  48         return xmlNewProp(node, BAD_CAST name, BAD_CAST value);
  49 }
  50 
  51 static xmlAttrPtr newNumProp(xmlNodePtr node, const char *name, int value)
  52 {
  53         char buf[256];
  54         snprintf(buf, 256, "%d", value);
  55         return newProp(node, name, buf);
  56 }
  57 
  58 static xmlAttrPtr newIdProp(xmlNodePtr node, const char *name, unsigned int id)
  59 {
  60         char buf[256];
  61         snprintf(buf, 256, "_%d", id);
  62         return newProp(node, name, buf);
  63 }
  64 
  65 static xmlNodePtr new_sym_node(struct symbol *sym, const char *name, xmlNodePtr parent)
  66 {
  67         xmlNodePtr node;
  68         const char *ident = show_ident(sym->ident);
  69 
  70         assert(name != NULL);
  71         assert(sym != NULL);
  72         assert(parent != NULL);
  73 
  74         node = xmlNewChild(parent, NULL, BAD_CAST "symbol", NULL);
  75 
  76         newProp(node, "type", name);
  77 
  78         newIdProp(node, "id", idcount);
  79 
  80         if (sym->ident && ident)
  81                 newProp(node, "ident", ident);
  82         newProp(node, "file", stream_name(sym->pos.stream));
  83 
  84         newNumProp(node, "start-line", sym->pos.line);
  85         newNumProp(node, "start-col", sym->pos.pos);
  86 
  87         if (sym->endpos.type) {
  88                 newNumProp(node, "end-line", sym->endpos.line);
  89                 newNumProp(node, "end-col", sym->endpos.pos);
  90                 if (sym->pos.stream != sym->endpos.stream)
  91                         newProp(node, "end-file", stream_name(sym->endpos.stream));
  92         }
  93         sym->aux = node;
  94 
  95         idcount++;
  96 
  97         return node;
  98 }
  99 
 100 static inline void examine_members(struct symbol_list *list, xmlNodePtr node)
 101 {
 102         struct symbol *sym;
 103 
 104         FOR_EACH_PTR(list, sym) {
 105                 examine_symbol(sym, node);
 106         } END_FOR_EACH_PTR(sym);
 107 }
 108 
 109 static void examine_modifiers(struct symbol *sym, xmlNodePtr node)
 110 {
 111         const char *modifiers[] = {
 112                         "auto",
 113                         "register",
 114                         "static",
 115                         "extern",
 116                         "const",
 117                         "volatile",
 118                         "signed",
 119                         "unsigned",
 120                         "char",
 121                         "short",
 122                         "long",
 123                         "long-long",
 124                         "typedef",
 125                         NULL,
 126                         NULL,
 127                         NULL,
 128                         NULL,
 129                         NULL,
 130                         "inline",
 131                         "addressable",
 132                         "nocast",
 133                         "noderef",
 134                         "accessed",
 135                         "toplevel",
 136                         "label",
 137                         "assigned",
 138                         "type-type",
 139                         "safe",
 140                         "user-type",
 141                         "force",
 142                         "explicitly-signed",
 143                         "bitwise"};
 144 
 145         int i;
 146 
 147         if (sym->namespace != NS_SYMBOL)
 148                 return;
 149 
 150         /*iterate over the 32 bit bitfield*/
 151         for (i=0; i < 32; i++) {
 152                 if ((sym->ctype.modifiers & 1<<i) && modifiers[i])
 153                         newProp(node, modifiers[i], "1");
 154         }
 155 }
 156 
 157 static void
 158 examine_layout(struct symbol *sym, xmlNodePtr node)
 159 {
 160         examine_symbol_type(sym);
 161 
 162         newNumProp(node, "bit-size", sym->bit_size);
 163         newNumProp(node, "alignment", sym->ctype.alignment);
 164         newNumProp(node, "offset", sym->offset);
 165         if (is_bitfield_type(sym)) {
 166                 newNumProp(node, "bit-offset", sym->bit_offset);
 167         }
 168 }
 169 
 170 static void examine_symbol(struct symbol *sym, xmlNodePtr node)
 171 {
 172         xmlNodePtr child = NULL;
 173         const char *base;
 174         int array_size;
 175 
 176         if (!sym)
 177                 return;
 178         if (sym->aux)                /*already visited */
 179                 return;
 180 
 181         if (sym->ident && sym->ident->reserved)
 182                 return;
 183 
 184         child = new_sym_node(sym, get_type_name(sym->type), node);
 185         examine_modifiers(sym, child);
 186         examine_layout(sym, child);
 187 
 188         if (sym->ctype.base_type) {
 189                 if ((base = builtin_typename(sym->ctype.base_type)) == NULL) {
 190                         if (!sym->ctype.base_type->aux) {
 191                                 examine_symbol(sym->ctype.base_type, root_node);
 192                         }
 193                         xmlNewProp(child, BAD_CAST "base-type",
 194                                    xmlGetProp((xmlNodePtr)sym->ctype.base_type->aux, BAD_CAST "id"));
 195                 } else {
 196                         newProp(child, "base-type-builtin", base);
 197                 }
 198         }
 199         if (sym->array_size) {
 200                 /* TODO: modify get_expression_value to give error return */
 201                 array_size = get_expression_value(sym->array_size);
 202                 newNumProp(child, "array-size", array_size);
 203         }
 204 
 205 
 206         switch (sym->type) {
 207         case SYM_STRUCT:
 208         case SYM_UNION:
 209                 examine_members(sym->symbol_list, child);
 210                 break;
 211         case SYM_FN:
 212                 examine_members(sym->arguments, child);
 213                 break;
 214         case SYM_UNINITIALIZED:
 215                 newProp(child, "base-type-builtin", builtin_typename(sym));
 216                 break;
 217         default:
 218                 break;
 219         }
 220         return;
 221 }
 222 
 223 static struct position *get_expansion_end (struct token *token)
 224 {
 225         struct token *p1, *p2;
 226 
 227         for (p1=NULL, p2=NULL;
 228              !eof_token(token);
 229              p2 = p1, p1 = token, token = token->next);
 230 
 231         if (p2)
 232                 return &(p2->pos);
 233         else
 234                 return NULL;
 235 }
 236 
 237 static void examine_macro(struct symbol *sym, xmlNodePtr node)
 238 {
 239         struct position *pos;
 240 
 241         /* this should probably go in the main codebase*/
 242         pos = get_expansion_end(sym->expansion);
 243         if (pos)
 244                 sym->endpos = *pos;
 245         else
 246                 sym->endpos = sym->pos;
 247 
 248         new_sym_node(sym, "macro", node);
 249 }
 250 
 251 static void examine_namespace(struct symbol *sym)
 252 {
 253         if (sym->ident && sym->ident->reserved)
 254                 return;
 255 
 256         switch(sym->namespace) {
 257         case NS_MACRO:
 258                 examine_macro(sym, root_node);
 259                 break;
 260         case NS_TYPEDEF:
 261         case NS_STRUCT:
 262         case NS_SYMBOL:
 263                 examine_symbol(sym, root_node);
 264                 break;
 265         case NS_NONE:
 266         case NS_LABEL:
 267         case NS_ITERATOR:
 268         case NS_UNDEF:
 269         case NS_PREPROCESSOR:
 270         case NS_KEYWORD:
 271                 break;
 272         default:
 273                 die("Unrecognised namespace type %d",sym->namespace);
 274         }
 275 
 276 }
 277 
 278 static int get_stream_id (const char *name)
 279 {
 280         int i;
 281         for (i=0; i<input_stream_nr; i++) {
 282                 if (strcmp(name, stream_name(i))==0)
 283                         return i;
 284         }
 285         return -1;
 286 }
 287 
 288 static inline void examine_symbol_list(const char *file, struct symbol_list *list)
 289 {
 290         struct symbol *sym;
 291         int stream_id = get_stream_id (file);
 292 
 293         if (!list)
 294                 return;
 295         FOR_EACH_PTR(list, sym) {
 296                 if (sym->pos.stream == stream_id)
 297                         examine_namespace(sym);
 298         } END_FOR_EACH_PTR(sym);
 299 }
 300 
 301 int main(int argc, char **argv)
 302 {
 303         struct string_list *filelist = NULL;
 304         struct symbol_list *symlist = NULL;
 305         char *file;
 306 
 307         doc = xmlNewDoc(BAD_CAST "1.0");
 308         root_node = xmlNewNode(NULL, BAD_CAST "parse");
 309         xmlDocSetRootElement(doc, root_node);
 310 
 311 /* - A DTD is probably unnecessary for something like this
 312 
 313         dtd = xmlCreateIntSubset(doc, "parse", "http://www.kernel.org/pub/software/devel/sparse/parse.dtd" NULL, "parse.dtd");
 314 
 315         ns = xmlNewNs (root_node, "http://www.kernel.org/pub/software/devel/sparse/parse.dtd", NULL);
 316 
 317         xmlSetNs(root_node, ns);
 318 */
 319         symlist = sparse_initialize(argc, argv, &filelist);
 320 
 321         FOR_EACH_PTR_NOTAG(filelist, file) {
 322                 examine_symbol_list(file, symlist);
 323                 sparse_keep_tokens(file);
 324                 examine_symbol_list(file, file_scope->symbols);
 325                 examine_symbol_list(file, global_scope->symbols);
 326         } END_FOR_EACH_PTR_NOTAG(file);
 327 
 328 
 329         xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
 330         xmlFreeDoc(doc);
 331         xmlCleanupParser();
 332 
 333         return 0;
 334 }