handle stuff like the kernel's WARN_ON() macro
[smatch.git] / c2xml.c
blob37f29cf9d22d91ca58a5d0ab4d02a738cf71c9c4
1 /*
2 * Sparse c2xml
4 * Dumps the parse tree as an xml document
6 * Copyright (C) 2007 Rob Taylor
8 * Licensed under the Open Software License version 1.1
9 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <assert.h>
16 #include <libxml/parser.h>
17 #include <libxml/tree.h>
19 #include "expression.h"
20 #include "parse.h"
21 #include "scope.h"
22 #include "symbol.h"
24 static xmlDocPtr doc = NULL; /* document pointer */
25 static xmlNodePtr root_node = NULL;/* root node pointer */
26 static int idcount = 0;
28 static void examine_symbol(struct symbol *sym, xmlNodePtr node);
30 static xmlAttrPtr newProp(xmlNodePtr node, const char *name, const char *value)
32 return xmlNewProp(node, BAD_CAST name, BAD_CAST value);
35 static xmlAttrPtr newNumProp(xmlNodePtr node, const char *name, int value)
37 char buf[256];
38 snprintf(buf, 256, "%d", value);
39 return newProp(node, name, buf);
42 static xmlAttrPtr newIdProp(xmlNodePtr node, const char *name, unsigned int id)
44 char buf[256];
45 snprintf(buf, 256, "_%d", id);
46 return newProp(node, name, buf);
49 static xmlNodePtr new_sym_node(struct symbol *sym, const char *name, xmlNodePtr parent)
51 xmlNodePtr node;
52 const char *ident = show_ident(sym->ident);
54 assert(name != NULL);
55 assert(sym != NULL);
56 assert(parent != NULL);
58 node = xmlNewChild(parent, NULL, BAD_CAST "symbol", NULL);
60 newProp(node, "type", name);
62 newIdProp(node, "id", idcount);
64 if (sym->ident && ident)
65 newProp(node, "ident", ident);
66 newProp(node, "file", stream_name(sym->pos.stream));
68 newNumProp(node, "start-line", sym->pos.line);
69 newNumProp(node, "start-col", sym->pos.pos);
71 if (sym->endpos.type) {
72 newNumProp(node, "end-line", sym->endpos.line);
73 newNumProp(node, "end-col", sym->endpos.pos);
74 if (sym->pos.stream != sym->endpos.stream)
75 newProp(node, "end-file", stream_name(sym->endpos.stream));
77 sym->aux = node;
79 idcount++;
81 return node;
84 static inline void examine_members(struct symbol_list *list, xmlNodePtr node)
86 struct symbol *sym;
88 FOR_EACH_PTR(list, sym) {
89 examine_symbol(sym, node);
90 } END_FOR_EACH_PTR(sym);
93 static void examine_modifiers(struct symbol *sym, xmlNodePtr node)
95 const char *modifiers[] = {
96 "auto",
97 "register",
98 "static",
99 "extern",
100 "const",
101 "volatile",
102 "signed",
103 "unsigned",
104 "char",
105 "short",
106 "long",
107 "long-long",
108 "typedef",
109 NULL,
110 NULL,
111 NULL,
112 NULL,
113 NULL,
114 "inline",
115 "addressable",
116 "nocast",
117 "noderef",
118 "accessed",
119 "toplevel",
120 "label",
121 "assigned",
122 "type-type",
123 "safe",
124 "user-type",
125 "force",
126 "explicitly-signed",
127 "bitwise"};
129 int i;
131 if (sym->namespace != NS_SYMBOL)
132 return;
134 /*iterate over the 32 bit bitfield*/
135 for (i=0; i < 32; i++) {
136 if ((sym->ctype.modifiers & 1<<i) && modifiers[i])
137 newProp(node, modifiers[i], "1");
141 static void
142 examine_layout(struct symbol *sym, xmlNodePtr node)
144 examine_symbol_type(sym);
146 newNumProp(node, "bit-size", sym->bit_size);
147 newNumProp(node, "alignment", sym->ctype.alignment);
148 newNumProp(node, "offset", sym->offset);
149 if (is_bitfield_type(sym)) {
150 newNumProp(node, "bit-offset", sym->bit_offset);
154 static void examine_symbol(struct symbol *sym, xmlNodePtr node)
156 xmlNodePtr child = NULL;
157 const char *base;
158 int array_size;
160 if (!sym)
161 return;
162 if (sym->aux) /*already visited */
163 return;
165 if (sym->ident && sym->ident->reserved)
166 return;
168 child = new_sym_node(sym, get_type_name(sym->type), node);
169 examine_modifiers(sym, child);
170 examine_layout(sym, child);
172 if (sym->ctype.base_type) {
173 if ((base = builtin_typename(sym->ctype.base_type)) == NULL) {
174 if (!sym->ctype.base_type->aux) {
175 examine_symbol(sym->ctype.base_type, root_node);
177 xmlNewProp(child, BAD_CAST "base-type",
178 xmlGetProp((xmlNodePtr)sym->ctype.base_type->aux, BAD_CAST "id"));
179 } else {
180 newProp(child, "base-type-builtin", base);
183 if (sym->array_size) {
184 /* TODO: modify get_expression_value to give error return */
185 array_size = get_expression_value(sym->array_size);
186 newNumProp(child, "array-size", array_size);
190 switch (sym->type) {
191 case SYM_STRUCT:
192 case SYM_UNION:
193 examine_members(sym->symbol_list, child);
194 break;
195 case SYM_FN:
196 examine_members(sym->arguments, child);
197 break;
198 case SYM_UNINITIALIZED:
199 newProp(child, "base-type-builtin", builtin_typename(sym));
200 break;
202 return;
205 static struct position *get_expansion_end (struct token *token)
207 struct token *p1, *p2;
209 for (p1=NULL, p2=NULL;
210 !eof_token(token);
211 p2 = p1, p1 = token, token = token->next);
213 if (p2)
214 return &(p2->pos);
215 else
216 return NULL;
219 static void examine_macro(struct symbol *sym, xmlNodePtr node)
221 xmlNodePtr child;
222 struct position *pos;
224 /* this should probably go in the main codebase*/
225 pos = get_expansion_end(sym->expansion);
226 if (pos)
227 sym->endpos = *pos;
228 else
229 sym->endpos = sym->pos;
231 child = new_sym_node(sym, "macro", node);
234 static void examine_namespace(struct symbol *sym)
236 if (sym->ident && sym->ident->reserved)
237 return;
239 switch(sym->namespace) {
240 case NS_MACRO:
241 examine_macro(sym, root_node);
242 break;
243 case NS_TYPEDEF:
244 case NS_STRUCT:
245 case NS_SYMBOL:
246 examine_symbol(sym, root_node);
247 break;
248 case NS_NONE:
249 case NS_LABEL:
250 case NS_ITERATOR:
251 case NS_UNDEF:
252 case NS_PREPROCESSOR:
253 case NS_KEYWORD:
254 break;
255 default:
256 die("Unrecognised namespace type %d",sym->namespace);
261 static int get_stream_id (const char *name)
263 int i;
264 for (i=0; i<input_stream_nr; i++) {
265 if (strcmp(name, stream_name(i))==0)
266 return i;
268 return -1;
271 static inline void examine_symbol_list(const char *file, struct symbol_list *list)
273 struct symbol *sym;
274 int stream_id = get_stream_id (file);
276 if (!list)
277 return;
278 FOR_EACH_PTR(list, sym) {
279 if (sym->pos.stream == stream_id)
280 examine_namespace(sym);
281 } END_FOR_EACH_PTR(sym);
284 int main(int argc, char **argv)
286 struct string_list *filelist = NULL;
287 struct symbol_list *symlist = NULL;
288 char *file;
290 doc = xmlNewDoc(BAD_CAST "1.0");
291 root_node = xmlNewNode(NULL, BAD_CAST "parse");
292 xmlDocSetRootElement(doc, root_node);
294 /* - A DTD is probably unnecessary for something like this
296 dtd = xmlCreateIntSubset(doc, "parse", "http://www.kernel.org/pub/software/devel/sparse/parse.dtd" NULL, "parse.dtd");
298 ns = xmlNewNs (root_node, "http://www.kernel.org/pub/software/devel/sparse/parse.dtd", NULL);
300 xmlSetNs(root_node, ns);
302 symlist = sparse_initialize(argc, argv, &filelist);
304 FOR_EACH_PTR_NOTAG(filelist, file) {
305 examine_symbol_list(file, symlist);
306 sparse_keep_tokens(file);
307 examine_symbol_list(file, file_scope->symbols);
308 examine_symbol_list(file, global_scope->symbols);
309 } END_FOR_EACH_PTR_NOTAG(file);
312 xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
313 xmlFreeDoc(doc);
314 xmlCleanupParser();
316 return 0;