2 * Example trivial client program that uses the sparse library
3 * to tokenize, preprocess and parse a C file, and prints out
6 * Copyright (C) 2003 Transmeta Corp.
7 * 2003-2004 Linus Torvalds
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 #include "expression.h"
41 #include "linearize.h"
43 static int context_increase(struct basic_block
*bb
, int entry
)
46 struct instruction
*insn
;
48 FOR_EACH_PTR(bb
->insns
, insn
) {
50 if (insn
->opcode
!= OP_CONTEXT
)
52 val
= insn
->increment
;
54 int current
= sum
+ entry
;
58 } else if (current
>= val
)
60 warning(insn
->pos
, "context check failure");
64 } END_FOR_EACH_PTR(insn
);
68 static int imbalance(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
, const char *why
)
71 struct symbol
*sym
= ep
->name
;
72 warning(bb
->pos
, "context imbalance in '%s' - %s", show_ident(sym
->ident
), why
);
77 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
);
79 static int check_children(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
81 struct instruction
*insn
;
82 struct basic_block
*child
;
84 insn
= last_instruction(bb
->insns
);
87 if (insn
->opcode
== OP_RET
)
88 return entry
!= exit
? imbalance(ep
, bb
, entry
, exit
, "wrong count at exit") : 0;
90 FOR_EACH_PTR(bb
->children
, child
) {
91 if (check_bb_context(ep
, child
, entry
, exit
))
93 } END_FOR_EACH_PTR(child
);
97 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
101 if (bb
->context
== entry
)
104 /* Now that's not good.. */
105 if (bb
->context
>= 0)
106 return imbalance(ep
, bb
, entry
, bb
->context
, "different lock contexts for basic block");
109 entry
+= context_increase(bb
, entry
);
111 return imbalance(ep
, bb
, entry
, exit
, "unexpected unlock");
113 return check_children(ep
, bb
, entry
, exit
);
116 static void check_cast_instruction(struct instruction
*insn
)
118 struct symbol
*orig_type
= insn
->orig_type
;
120 int old
= orig_type
->bit_size
;
121 int new = insn
->size
;
122 int oldsigned
= (orig_type
->ctype
.modifiers
& MOD_SIGNED
) != 0;
123 int newsigned
= insn
->opcode
== OP_SCAST
;
126 if (oldsigned
== newsigned
)
130 warning(insn
->pos
, "cast loses sign");
134 warning(insn
->pos
, "cast drops bits");
137 if (oldsigned
== newsigned
) {
138 warning(insn
->pos
, "cast wasn't removed");
141 warning(insn
->pos
, "cast changes sign");
145 static void check_range_instruction(struct instruction
*insn
)
147 warning(insn
->pos
, "value out of range");
150 static void check_byte_count(struct instruction
*insn
, pseudo_t count
)
154 if (count
->type
== PSEUDO_VAL
) {
155 long long val
= count
->value
;
156 if (val
<= 0 || val
> 100000)
157 warning(insn
->pos
, "%s with byte count of %lld",
158 show_ident(insn
->func
->sym
->ident
), val
);
161 /* OK, we could try to do the range analysis here */
164 static pseudo_t
argument(struct instruction
*call
, unsigned int argno
)
167 struct ptr_list
*arg_list
= (struct ptr_list
*) call
->arguments
;
170 if (linearize_ptr_list(arg_list
, (void *)args
, 8) > argno
)
175 static void check_memset(struct instruction
*insn
)
177 check_byte_count(insn
, argument(insn
, 3));
180 #define check_memcpy check_memset
181 #define check_ctu check_memset
182 #define check_cfu check_memset
186 void (*check
)(struct instruction
*insn
);
189 static void check_call_instruction(struct instruction
*insn
)
191 pseudo_t fn
= insn
->func
;
193 static const struct checkfn check_fn
[] = {
194 { &memset_ident
, check_memset
},
195 { &memcpy_ident
, check_memcpy
},
196 { ©_to_user_ident
, check_ctu
},
197 { ©_from_user_ident
, check_cfu
},
201 if (fn
->type
!= PSEUDO_SYM
)
203 ident
= fn
->sym
->ident
;
206 for (i
= 0; i
< ARRAY_SIZE(check_fn
); i
++) {
207 if (check_fn
[i
].id
!= ident
)
209 check_fn
[i
].check(insn
);
214 static void check_one_instruction(struct instruction
*insn
)
216 switch (insn
->opcode
) {
217 case OP_CAST
: case OP_SCAST
:
219 check_cast_instruction(insn
);
222 check_range_instruction(insn
);
225 check_call_instruction(insn
);
232 static void check_bb_instructions(struct basic_block
*bb
)
234 struct instruction
*insn
;
235 FOR_EACH_PTR(bb
->insns
, insn
) {
238 check_one_instruction(insn
);
239 } END_FOR_EACH_PTR(insn
);
242 static void check_instructions(struct entrypoint
*ep
)
244 struct basic_block
*bb
;
245 FOR_EACH_PTR(ep
->bbs
, bb
) {
246 check_bb_instructions(bb
);
247 } END_FOR_EACH_PTR(bb
);
250 static void check_context(struct entrypoint
*ep
)
252 struct symbol
*sym
= ep
->name
;
253 struct context
*context
;
254 unsigned int in_context
= 0, out_context
= 0;
256 if (Wuninitialized
&& verbose
&& ep
->entry
->bb
->needs
) {
258 FOR_EACH_PTR(ep
->entry
->bb
->needs
, pseudo
) {
259 if (pseudo
->type
!= PSEUDO_ARG
)
260 warning(sym
->pos
, "%s: possible uninitialized variable (%s)",
261 show_ident(sym
->ident
), show_pseudo(pseudo
));
262 } END_FOR_EACH_PTR(pseudo
);
265 check_instructions(ep
);
267 FOR_EACH_PTR(sym
->ctype
.contexts
, context
) {
268 in_context
+= context
->in
;
269 out_context
+= context
->out
;
270 } END_FOR_EACH_PTR(context
);
271 check_bb_context(ep
, ep
->entry
->bb
, in_context
, out_context
);
274 static void check_symbols(struct symbol_list
*list
)
278 FOR_EACH_PTR(list
, sym
) {
279 struct entrypoint
*ep
;
282 ep
= linearize_symbol(sym
);
289 } END_FOR_EACH_PTR(sym
);
291 if (Wsparse_error
&& die_if_error
)
295 int main(int argc
, char **argv
)
297 struct string_list
*filelist
= NULL
;
300 // Expand, linearize and show it.
301 check_symbols(sparse_initialize(argc
, argv
, &filelist
));
302 FOR_EACH_PTR_NOTAG(filelist
, file
) {
303 check_symbols(sparse(file
));
304 } END_FOR_EACH_PTR_NOTAG(file
);