2 * Example trivial client program that uses the sparse library
3 * to tokenize, pre-process and parse a C file, and prints out
6 * Copyright (C) 2003 Transmeta Corp.
7 * 2003-2004 Linus Torvalds
9 * Licensed under the Open Software License version 1.1
24 #include "expression.h"
25 #include "linearize.h"
27 static int context_increase(struct basic_block
*bb
, int entry
)
30 struct instruction
*insn
;
32 FOR_EACH_PTR(bb
->insns
, insn
) {
34 if (insn
->opcode
!= OP_CONTEXT
)
36 val
= insn
->increment
;
38 int current
= sum
+ entry
;
42 } else if (current
>= val
)
44 warning(insn
->pos
, "context check failure");
48 } END_FOR_EACH_PTR(insn
);
52 static int imbalance(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
, const char *why
)
55 struct symbol
*sym
= ep
->name
;
56 warning(bb
->pos
, "context imbalance in '%s' - %s", show_ident(sym
->ident
), why
);
61 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
);
63 static int check_children(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
65 struct instruction
*insn
;
66 struct basic_block
*child
;
68 insn
= last_instruction(bb
->insns
);
71 if (insn
->opcode
== OP_RET
)
72 return entry
!= exit
? imbalance(ep
, bb
, entry
, exit
, "wrong count at exit") : 0;
74 FOR_EACH_PTR(bb
->children
, child
) {
75 if (check_bb_context(ep
, child
, entry
, exit
))
77 } END_FOR_EACH_PTR(child
);
81 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
85 if (bb
->context
== entry
)
88 /* Now that's not good.. */
90 return imbalance(ep
, bb
, entry
, bb
->context
, "different lock contexts for basic block");
93 entry
+= context_increase(bb
, entry
);
95 return imbalance(ep
, bb
, entry
, exit
, "unexpected unlock");
97 return check_children(ep
, bb
, entry
, exit
);
100 static void check_cast_instruction(struct instruction
*insn
)
102 struct symbol
*orig_type
= insn
->orig_type
;
104 int old
= orig_type
->bit_size
;
105 int new = insn
->size
;
106 int oldsigned
= (orig_type
->ctype
.modifiers
& MOD_SIGNED
) != 0;
107 int newsigned
= insn
->opcode
== OP_SCAST
;
110 if (oldsigned
== newsigned
)
114 warning(insn
->pos
, "cast loses sign");
118 warning(insn
->pos
, "cast drops bits");
121 if (oldsigned
== newsigned
) {
122 warning(insn
->pos
, "cast wasn't removed");
125 warning(insn
->pos
, "cast changes sign");
129 static void check_range_instruction(struct instruction
*insn
)
131 warning(insn
->pos
, "value out of range");
134 static void check_byte_count(struct instruction
*insn
, pseudo_t count
)
138 if (count
->type
== PSEUDO_VAL
) {
139 long long val
= count
->value
;
140 if (val
<= 0 || val
> 100000)
141 warning(insn
->pos
, "%s with byte count of %lld",
142 show_ident(insn
->func
->sym
->ident
), val
);
145 /* Ok, we could try to do the range analysis here */
148 static pseudo_t
argument(struct instruction
*call
, unsigned int argno
)
151 struct ptr_list
*arg_list
= (struct ptr_list
*) call
->arguments
;
154 if (linearize_ptr_list(arg_list
, (void *)args
, 8) > argno
)
159 static void check_memset(struct instruction
*insn
)
161 check_byte_count(insn
, argument(insn
, 3));
164 #define check_memcpy check_memset
165 #define check_ctu check_memset
166 #define check_cfu check_memset
170 void (*check
)(struct instruction
*insn
);
173 static void check_call_instruction(struct instruction
*insn
)
175 pseudo_t fn
= insn
->func
;
177 static const struct checkfn check_fn
[] = {
178 { &memset_ident
, check_memset
},
179 { &memcpy_ident
, check_memcpy
},
180 { ©_to_user_ident
, check_ctu
},
181 { ©_from_user_ident
, check_cfu
},
185 if (fn
->type
!= PSEUDO_SYM
)
187 ident
= fn
->sym
->ident
;
190 for (i
= 0; i
< sizeof(check_fn
)/sizeof(struct checkfn
) ; i
++) {
191 if (check_fn
[i
].id
!= ident
)
193 check_fn
[i
].check(insn
);
198 static void check_one_instruction(struct instruction
*insn
)
200 switch (insn
->opcode
) {
201 case OP_CAST
: case OP_SCAST
:
203 check_cast_instruction(insn
);
206 check_range_instruction(insn
);
209 check_call_instruction(insn
);
216 static void check_bb_instructions(struct basic_block
*bb
)
218 struct instruction
*insn
;
219 FOR_EACH_PTR(bb
->insns
, insn
) {
222 check_one_instruction(insn
);
223 } END_FOR_EACH_PTR(insn
);
226 static void check_instructions(struct entrypoint
*ep
)
228 struct basic_block
*bb
;
229 FOR_EACH_PTR(ep
->bbs
, bb
) {
230 check_bb_instructions(bb
);
231 } END_FOR_EACH_PTR(bb
);
234 static void check_context(struct entrypoint
*ep
)
236 struct symbol
*sym
= ep
->name
;
237 struct context
*context
;
238 unsigned int in_context
= 0, out_context
= 0;
240 if (Wuninitialized
&& verbose
&& ep
->entry
->bb
->needs
) {
242 FOR_EACH_PTR(ep
->entry
->bb
->needs
, pseudo
) {
243 if (pseudo
->type
!= PSEUDO_ARG
)
244 warning(sym
->pos
, "%s: possible uninitialized variable (%s)",
245 show_ident(sym
->ident
), show_pseudo(pseudo
));
246 } END_FOR_EACH_PTR(pseudo
);
249 check_instructions(ep
);
251 FOR_EACH_PTR(sym
->ctype
.contexts
, context
) {
252 in_context
+= context
->in
;
253 out_context
+= context
->out
;
254 } END_FOR_EACH_PTR(context
);
255 check_bb_context(ep
, ep
->entry
->bb
, in_context
, out_context
);
258 static void check_symbols(struct symbol_list
*list
)
262 FOR_EACH_PTR(list
, sym
) {
263 struct entrypoint
*ep
;
266 ep
= linearize_symbol(sym
);
273 } END_FOR_EACH_PTR(sym
);
276 int main(int argc
, char **argv
)
278 struct string_list
*filelist
= NULL
;
281 // Expand, linearize and show it.
282 check_symbols(sparse_initialize(argc
, argv
, &filelist
));
283 FOR_EACH_PTR_NOTAG(filelist
, file
) {
284 check_symbols(sparse(file
));
285 } END_FOR_EACH_PTR_NOTAG(file
);