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
) {
52 if (insn
->opcode
!= OP_CONTEXT
)
54 val
= insn
->increment
;
56 int current
= sum
+ entry
;
60 } else if (current
>= val
)
62 warning(insn
->pos
, "context check failure");
66 } END_FOR_EACH_PTR(insn
);
70 static int imbalance(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
, const char *why
)
73 struct symbol
*sym
= ep
->name
;
74 warning(bb
->pos
, "context imbalance in '%s' - %s", show_ident(sym
->ident
), why
);
79 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
);
81 static int check_children(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
83 struct instruction
*insn
;
84 struct basic_block
*child
;
86 insn
= last_instruction(bb
->insns
);
89 if (insn
->opcode
== OP_RET
)
90 return entry
!= exit
? imbalance(ep
, bb
, entry
, exit
, "wrong count at exit") : 0;
92 FOR_EACH_PTR(bb
->children
, child
) {
93 if (check_bb_context(ep
, child
, entry
, exit
))
95 } END_FOR_EACH_PTR(child
);
99 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
103 if (bb
->context
== entry
)
106 /* Now that's not good.. */
107 if (bb
->context
>= 0)
108 return imbalance(ep
, bb
, entry
, bb
->context
, "different lock contexts for basic block");
111 entry
+= context_increase(bb
, entry
);
113 return imbalance(ep
, bb
, entry
, exit
, "unexpected unlock");
115 return check_children(ep
, bb
, entry
, exit
);
118 static void check_cast_instruction(struct instruction
*insn
)
120 struct symbol
*orig_type
= insn
->orig_type
;
122 int old
= orig_type
->bit_size
;
123 int new = insn
->size
;
124 int oldsigned
= (orig_type
->ctype
.modifiers
& MOD_SIGNED
) != 0;
125 int newsigned
= insn
->opcode
== OP_SEXT
;
128 if (oldsigned
== newsigned
)
132 warning(insn
->pos
, "cast loses sign");
136 warning(insn
->pos
, "cast drops bits");
139 if (oldsigned
== newsigned
) {
140 warning(insn
->pos
, "cast wasn't removed");
143 warning(insn
->pos
, "cast changes sign");
147 static void check_range_instruction(struct instruction
*insn
)
149 warning(insn
->pos
, "value out of range");
152 static void check_byte_count(struct instruction
*insn
, pseudo_t count
)
156 if (count
->type
== PSEUDO_VAL
) {
157 unsigned long long val
= count
->value
;
158 if (Wmemcpy_max_count
&& val
> fmemcpy_max_count
)
159 warning(insn
->pos
, "%s with byte count of %llu",
160 show_ident(insn
->func
->sym
->ident
), val
);
163 /* OK, we could try to do the range analysis here */
166 static pseudo_t
argument(struct instruction
*call
, unsigned int argno
)
169 struct ptr_list
*arg_list
= (struct ptr_list
*) call
->arguments
;
172 if (linearize_ptr_list(arg_list
, (void *)args
, 8) > argno
)
177 static void check_memset(struct instruction
*insn
)
179 check_byte_count(insn
, argument(insn
, 3));
182 #define check_memcpy check_memset
183 #define check_ctu check_memset
184 #define check_cfu check_memset
188 void (*check
)(struct instruction
*insn
);
191 static void check_call_instruction(struct instruction
*insn
)
193 pseudo_t fn
= insn
->func
;
195 static const struct checkfn check_fn
[] = {
196 { &memset_ident
, check_memset
},
197 { &memcpy_ident
, check_memcpy
},
198 { ©_to_user_ident
, check_ctu
},
199 { ©_from_user_ident
, check_cfu
},
203 if (fn
->type
!= PSEUDO_SYM
)
205 ident
= fn
->sym
->ident
;
208 for (i
= 0; i
< ARRAY_SIZE(check_fn
); i
++) {
209 if (check_fn
[i
].id
!= ident
)
211 check_fn
[i
].check(insn
);
216 static void check_one_instruction(struct instruction
*insn
)
218 switch (insn
->opcode
) {
219 case OP_SEXT
: case OP_ZEXT
:
222 check_cast_instruction(insn
);
225 check_range_instruction(insn
);
228 check_call_instruction(insn
);
235 static void check_bb_instructions(struct basic_block
*bb
)
237 struct instruction
*insn
;
238 FOR_EACH_PTR(bb
->insns
, insn
) {
241 check_one_instruction(insn
);
242 } END_FOR_EACH_PTR(insn
);
245 static void check_instructions(struct entrypoint
*ep
)
247 struct basic_block
*bb
;
248 FOR_EACH_PTR(ep
->bbs
, bb
) {
250 check_bb_instructions(bb
);
251 } END_FOR_EACH_PTR(bb
);
254 static void check_context(struct entrypoint
*ep
)
256 struct symbol
*sym
= ep
->name
;
257 struct context
*context
;
258 unsigned int in_context
= 0, out_context
= 0;
260 if (Wuninitialized
&& verbose
&& ep
->entry
->bb
->needs
) {
262 FOR_EACH_PTR(ep
->entry
->bb
->needs
, pseudo
) {
263 if (pseudo
->type
!= PSEUDO_ARG
)
264 warning(sym
->pos
, "%s: possible uninitialized variable (%s)",
265 show_ident(sym
->ident
), show_pseudo(pseudo
));
266 } END_FOR_EACH_PTR(pseudo
);
269 check_instructions(ep
);
271 FOR_EACH_PTR(sym
->ctype
.contexts
, context
) {
272 in_context
+= context
->in
;
273 out_context
+= context
->out
;
274 } END_FOR_EACH_PTR(context
);
275 check_bb_context(ep
, ep
->entry
->bb
, in_context
, out_context
);
278 /* list_compound_symbol - symbol info for arrays, structures, unions */
279 static void list_compound_symbol(struct symbol
*sym
)
283 /* Only show symbols that have a positive size */
284 if (sym
->bit_size
<= 0)
286 if (!sym
->ctype
.base_type
)
288 /* Don't show unnamed types */
292 if (sym
->type
== SYM_NODE
)
293 base
= sym
->ctype
.base_type
;
296 switch (base
->type
) {
297 case SYM_STRUCT
: case SYM_UNION
: case SYM_ARRAY
:
303 info(sym
->pos
, "%s: compound size %u, alignment %lu",
305 bits_to_bytes(sym
->bit_size
),
306 sym
->ctype
.alignment
);
309 static void check_symbols(struct symbol_list
*list
)
313 FOR_EACH_PTR(list
, sym
) {
314 struct entrypoint
*ep
;
317 ep
= linearize_symbol(sym
);
318 if (ep
&& ep
->entry
) {
325 list_compound_symbol(sym
);
326 } END_FOR_EACH_PTR(sym
);
328 if (Wsparse_error
&& die_if_error
)
332 int main(int argc
, char **argv
)
334 struct string_list
*filelist
= NULL
;
337 // by default ignore -o <file>
340 // Expand, linearize and show it.
341 check_symbols(sparse_initialize(argc
, argv
, &filelist
));
342 FOR_EACH_PTR(filelist
, file
) {
343 check_symbols(sparse(file
));
344 } END_FOR_EACH_PTR(file
);