comparison: fix how addresses are handled
[smatch.git] / lib.c
blobc15f3793fa6bdc855a4ff3998578dfb78133bbdc
1 /*
2 * 'sparse' library helper routines.
4 * Copyright (C) 2003 Transmeta Corp.
5 * 2003-2004 Linus Torvalds
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
25 #include <ctype.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdarg.h>
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <assert.h>
36 #include <sys/types.h>
38 #include "lib.h"
39 #include "allocate.h"
40 #include "token.h"
41 #include "parse.h"
42 #include "symbol.h"
43 #include "expression.h"
44 #include "evaluate.h"
45 #include "scope.h"
46 #include "linearize.h"
47 #include "target.h"
48 #include "machine.h"
49 #include "version.h"
50 #include "bits.h"
52 int parse_error;
54 static int prettify(const char **fnamep)
56 const char *name = *fnamep;
57 int len = strlen(name);
59 if (len > 2 && !memcmp(name, "./", 2)) {
60 name += 2;
61 len -= 2;
64 *fnamep = name;
65 return len;
68 static const char *show_include_chain(int stream, const char *base)
70 static char buffer[200];
71 int len = 0;
73 while ((stream = stream_prev(stream)) >= 0) {
74 const char *p = stream_name(stream);
75 int pretty_len;
77 if (p == base)
78 break;
80 pretty_len = prettify(&p);
81 if (pretty_len <= 0)
82 break;
85 * At worst, we'll need " (through %s, ...)" in addition to the
86 * new filename
88 if (pretty_len + len + 20 > sizeof(buffer)) {
89 if (!len)
90 return "";
91 memcpy(buffer+len, ", ...", 5);
92 len += 5;
93 break;
96 if (!len) {
97 memcpy(buffer, " (through ", 10);
98 len = 10;
99 } else {
100 buffer[len++] = ',';
101 buffer[len++] = ' ';
104 memcpy(buffer+len, p, pretty_len);
105 len += pretty_len;
107 if (!len)
108 return "";
110 buffer[len] = ')';
111 buffer[len+1] = 0;
112 return buffer;
115 static const char *show_stream_name(struct position pos)
117 const char *name = stream_name(pos.stream);
118 static const char *last;
120 if (name == base_filename)
121 return name;
122 if (name == last)
123 return name;
124 last = name;
126 fprintf(stderr, "%s: note: in included file%s:\n",
127 base_filename,
128 show_include_chain(pos.stream, base_filename));
129 return name;
132 static void do_warn(const char *type, struct position pos, const char * fmt, va_list args)
134 static char buffer[512];
136 /* Shut up warnings if position is bad_token.pos */
137 if (pos.type == TOKEN_BAD)
138 return;
140 vsprintf(buffer, fmt, args);
142 fflush(stdout);
143 fprintf(stderr, "%s:%d:%d: %s%s%s\n",
144 show_stream_name(pos), pos.line, pos.pos,
145 diag_prefix, type, buffer);
148 static int show_info = 1;
150 void info(struct position pos, const char * fmt, ...)
152 va_list args;
154 if (!show_info)
155 return;
156 va_start(args, fmt);
157 do_warn("", pos, fmt, args);
158 va_end(args);
161 static void do_error(struct position pos, const char * fmt, va_list args)
163 static int errors = 0;
165 parse_error = 1;
166 die_if_error = 1;
167 show_info = 1;
168 /* Shut up warnings if position is bad_token.pos */
169 if (pos.type == TOKEN_BAD)
170 return;
171 /* Shut up warnings after an error */
172 has_error |= ERROR_CURR_PHASE;
173 if (errors > fmax_errors) {
174 static int once = 0;
175 show_info = 0;
176 if (once)
177 return;
178 fmt = "too many errors";
179 once = 1;
182 do_warn("error: ", pos, fmt, args);
183 errors++;
186 void warning(struct position pos, const char * fmt, ...)
188 va_list args;
190 if (Wsparse_error) {
191 va_start(args, fmt);
192 do_error(pos, fmt, args);
193 va_end(args);
194 return;
197 if (!fmax_warnings || has_error) {
198 show_info = 0;
199 return;
202 if (!--fmax_warnings) {
203 show_info = 0;
204 fmt = "too many warnings";
207 va_start(args, fmt);
208 do_warn("warning: ", pos, fmt, args);
209 va_end(args);
212 void sparse_error(struct position pos, const char * fmt, ...)
214 va_list args;
215 va_start(args, fmt);
216 do_error(pos, fmt, args);
217 va_end(args);
220 void expression_error(struct expression *expr, const char *fmt, ...)
222 va_list args;
223 va_start(args, fmt);
224 do_error(expr->pos, fmt, args);
225 va_end(args);
226 expr->ctype = &bad_ctype;
229 NORETURN_ATTR
230 void error_die(struct position pos, const char * fmt, ...)
232 va_list args;
233 va_start(args, fmt);
234 do_warn("error: ", pos, fmt, args);
235 va_end(args);
236 exit(1);
239 NORETURN_ATTR
240 void die(const char *fmt, ...)
242 va_list args;
243 static char buffer[512];
245 va_start(args, fmt);
246 vsnprintf(buffer, sizeof(buffer), fmt, args);
247 va_end(args);
249 fprintf(stderr, "%s%s\n", diag_prefix, buffer);
250 exit(1);
253 ////////////////////////////////////////////////////////////////////////////////
255 static struct token *pre_buffer_begin = NULL;
256 static struct token **pre_buffer_next = &pre_buffer_begin;
258 void add_pre_buffer(const char *fmt, ...)
260 va_list args;
261 unsigned int size;
262 struct token *begin, *end;
263 char buffer[4096];
265 va_start(args, fmt);
266 size = vsnprintf(buffer, sizeof(buffer), fmt, args);
267 va_end(args);
268 begin = tokenize_buffer(buffer, size, &end);
269 *pre_buffer_next = begin;
270 pre_buffer_next = &end->next;
273 static void create_builtin_stream(void)
275 // Temporary hack
276 add_pre_buffer("#define _Pragma(x)\n");
278 /* add the multiarch include directories, if any */
279 if (multiarch_dir && *multiarch_dir) {
280 add_pre_buffer("#add_system \"/usr/include/%s\"\n", multiarch_dir);
281 add_pre_buffer("#add_system \"/usr/local/include/%s\"\n", multiarch_dir);
284 /* We add compiler headers path here because we have to parse
285 * the arguments to get it, falling back to default. */
286 add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
287 add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
289 add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
290 add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
291 add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
292 add_pre_buffer("#define __builtin_va_arg(arg,type) ({ type __va_arg_ret = *(type *)(arg); arg += sizeof(type); __va_arg_ret; })\n");
293 add_pre_buffer("#define __builtin_va_alist (*(void *)0)\n");
294 add_pre_buffer("#define __builtin_va_arg_incr(x) ((x) + 1)\n");
295 add_pre_buffer("#define __builtin_va_copy(dest, src) ({ dest = src; (void)0; })\n");
296 add_pre_buffer("#define __builtin_ms_va_copy(dest, src) ({ dest = src; (void)0; })\n");
297 add_pre_buffer("#define __builtin_va_end(arg)\n");
298 add_pre_buffer("#define __builtin_ms_va_end(arg)\n");
299 add_pre_buffer("#define __builtin_va_arg_pack()\n");
302 static struct symbol_list *sparse_tokenstream(struct token *token)
304 int builtin = token && !token->pos.stream;
306 // Preprocess the stream
307 token = preprocess(token);
309 if (dump_macro_defs || dump_macros_only) {
310 if (!builtin)
311 dump_macro_definitions();
312 if (dump_macros_only)
313 return NULL;
316 if (preprocess_only) {
317 while (!eof_token(token)) {
318 int prec = 1;
319 struct token *next = token->next;
320 const char *separator = "";
321 if (next->pos.whitespace)
322 separator = " ";
323 if (next->pos.newline) {
324 separator = "\n\t\t\t\t\t";
325 prec = next->pos.pos;
326 if (prec > 4)
327 prec = 4;
329 printf("%s%.*s", show_token(token), prec, separator);
330 token = next;
332 putchar('\n');
334 return NULL;
337 // Parse the resulting C code
338 while (!eof_token(token))
339 token = external_declaration(token, &translation_unit_used_list, NULL);
340 return translation_unit_used_list;
343 static struct symbol_list *sparse_file(const char *filename)
345 int fd;
346 struct token *token;
348 if (strcmp(filename, "-") == 0) {
349 fd = 0;
350 } else {
351 fd = open(filename, O_RDONLY);
352 if (fd < 0)
353 die("No such file: %s", filename);
355 base_filename = filename;
357 // Tokenize the input stream
358 token = tokenize(NULL, filename, fd, NULL, includepath);
359 store_all_tokens(token);
361 close(fd);
363 return sparse_tokenstream(token);
367 * This handles the "-include" directive etc: we're in global
368 * scope, and all types/macros etc will affect all the following
369 * files.
371 * NOTE NOTE NOTE! "#undef" of anything in this stage will
372 * affect all subsequent files too, i.e. we can have non-local
373 * behaviour between files!
375 static struct symbol_list *sparse_initial(void)
377 int i;
379 // Prepend any "include" file to the stream.
380 // We're in global scope, it will affect all files!
381 for (i = 0; i < cmdline_include_nr; i++)
382 add_pre_buffer("#argv_include \"%s\"\n", cmdline_include[i]);
384 return sparse_tokenstream(pre_buffer_begin);
387 struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **filelist)
389 char **args;
390 struct symbol_list *list;
392 base_filename = "command-line";
394 // Initialize symbol stream first, so that we can add defines etc
395 init_symbols();
396 init_include_path();
398 // initialize the default target to the native 'machine'
399 target_config(MACH_NATIVE);
401 args = argv;
402 for (;;) {
403 char *arg = *++args;
404 if (!arg)
405 break;
407 if (arg[0] == '-' && arg[1]) {
408 args = handle_switch(arg+1, args);
409 continue;
411 add_ptr_list(filelist, arg);
413 handle_switch_finalize();
415 // Redirect stdout if needed
416 if (dump_macro_defs || preprocess_only)
417 do_output = 1;
418 if (do_output && outfile && strcmp(outfile, "-")) {
419 if (!freopen(outfile, "w", stdout))
420 die("error: cannot open %s: %s", outfile, strerror(errno));
423 if (fdump_ir == 0)
424 fdump_ir = PASS_FINAL;
426 list = NULL;
427 if (filelist) {
428 // Initialize type system
429 target_init();
430 init_ctype();
432 predefined_macros();
433 create_builtin_stream();
434 init_builtins(0);
436 list = sparse_initial();
439 * Protect the initial token allocations, since
440 * they need to survive all the others
442 protect_token_alloc();
445 * Evaluate the complete symbol list
446 * Note: This is not needed for normal cases.
447 * These symbols should only be predefined defines and
448 * declaratons which will be evaluated later, when needed.
449 * This is also the case when a file is directly included via
450 * '-include <file>' on the command line *AND* the file only
451 * contains defines, declarations and inline definitions.
452 * However, in the rare cases where the given file should
453 * contain some definitions, these will never be evaluated
454 * and thus won't be able to be linearized correctly.
455 * Hence the evaluate_symbol_list() here under.
457 evaluate_symbol_list(list);
458 return list;
461 struct symbol_list * sparse_keep_tokens(char *filename)
463 struct symbol_list *res;
465 /* Clear previous symbol list */
466 translation_unit_used_list = NULL;
468 new_file_scope();
469 res = sparse_file(filename);
471 /* And return it */
472 return res;
476 struct symbol_list * __sparse(char *filename)
478 struct symbol_list *res;
480 res = sparse_keep_tokens(filename);
482 /* Drop the tokens for this file after parsing */
483 clear_token_alloc();
485 /* And return it */
486 return res;
489 struct symbol_list * sparse(char *filename)
491 struct symbol_list *res = __sparse(filename);
493 if (has_error & ERROR_CURR_PHASE)
494 has_error = ERROR_PREV_PHASE;
495 /* Evaluate the complete symbol list */
496 evaluate_symbol_list(res);
498 return res;