xref: /illumos-gate/usr/src/tools/smatch/src/c2xml.c (revision 856f710c9dc323b39da5935194d7928ffb99b67f)
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 }
335