Make "check" a bit nicer about checking kernel files:
[smatch.git] / check.c
blob727724965d941eaf0283b96077c8fc6d85173a01
1 /*
2 * Example trivial client program that uses the sparse library
3 * to tokenize, pre-process and parse a C file, and prints out
4 * the results.
6 * Copyright (C) 2003 Transmeta Corp.
8 * Licensed under the Open Software License version 1.1
9 */
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <unistd.h>
16 #include <fcntl.h>
18 #include "lib.h"
19 #include "token.h"
20 #include "parse.h"
21 #include "symbol.h"
22 #include "expression.h"
24 static unsigned int pre_buffer_size = 0;
25 static unsigned char pre_buffer[8192];
27 static char *include = NULL;
28 static int include_fd = -1;
30 static void add_pre_buffer(const char *fmt, ...)
32 va_list args;
33 unsigned int size;
35 va_start(args, fmt);
36 size = pre_buffer_size;
37 size += vsnprintf(pre_buffer + size,
38 sizeof(pre_buffer) - size,
39 fmt, args);
40 pre_buffer_size = size;
41 va_end(args);
44 static char ** handle_switch(char *arg, char **next)
46 switch (*arg) {
47 case 'D': {
48 const char *name = arg+1;
49 const char *value = "";
50 for (;;) {
51 char c;
52 c = *++arg;
53 if (!c)
54 break;
55 if (isspace(c) || c == '=') {
56 *arg = '\0';
57 value = arg+1;
58 break;
61 add_pre_buffer("#define %s %s\n", name, value);
62 return next;
65 case 'I':
66 add_pre_buffer("#add_include \"%s/\"\n", arg+1);
67 return next;
68 case 'i':
69 if (*next && !strcmp(arg, "include")) {
70 char *name = *++next;
71 int fd = open(name, O_RDONLY);
72 include_fd = fd;
73 include = name;
74 if (fd < 0)
75 perror(name);
76 return next;
78 /* Fallthrough */
79 default:
80 /* Ignore unknown command line options - they're probably gcc switches */
82 return next;
85 static void clean_up_symbol(struct symbol *sym, void *_parent, int flags)
87 evaluate_symbol(sym);
90 int main(int argc, char **argv)
92 int fd;
93 char *filename = NULL, **args;
94 struct token *token;
96 // Initialize symbol stream first, so that we can add defines etc
97 init_symbols();
99 add_pre_buffer("#define __CHECKER__ 1\n");
100 add_pre_buffer("#define cond_syscall(x)\n");
101 add_pre_buffer("#nostdinc\n");
102 add_pre_buffer("#add_include \"/home/torvalds/v2.5/linux/include/\"\n");
103 add_pre_buffer("#add_include \"/home/torvalds/v2.5/linux/include/asm-i386/mach-default/\"\n");
104 add_pre_buffer("#add_include \"/home/torvalds/v2.5/linux/arch/i386/mach-default/\"\n");
105 add_pre_buffer("#add_include \"\"\n");
106 add_pre_buffer("#define __KERNEL__\n");
107 add_pre_buffer("#define __GNUC__ 2\n");
108 add_pre_buffer("#define __GNUC_MINOR__ 95\n");
109 add_pre_buffer("#define __builtin_constant_p(x) 0\n");
110 add_pre_buffer("#define __func__ \"function\"\n");
111 add_pre_buffer("#define __extension__\n");
113 args = argv;
114 for (;;) {
115 char *arg = *++args;
116 if (!arg)
117 break;
118 if (arg[0] == '-') {
119 args = handle_switch(arg+1, args);
120 continue;
122 filename = arg;
126 fd = open(filename, O_RDONLY);
127 if (fd < 0)
128 die("No such file: %s", argv[1]);
130 // Tokenize the input stream
131 token = tokenize(filename, fd, NULL);
132 close(fd);
134 // Prepend any "include" file to the stream.
135 if (include_fd >= 0)
136 token = tokenize(include, include_fd, token);
138 // Prepend the initial built-in stream
139 token = tokenize_buffer(pre_buffer, pre_buffer_size, token);
141 // Pre-process the stream
142 token = preprocess(token);
144 // Parse the resulting C code
145 translation_unit(token, &used_list);
147 // Do type evaluation and simplify
148 symbol_iterate(used_list, clean_up_symbol, NULL);
149 return 0;