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
)
30 struct instruction
*insn
;
32 FOR_EACH_PTR(bb
->insns
, insn
) {
33 if (insn
->opcode
== OP_CONTEXT
)
34 sum
+= insn
->increment
;
35 } END_FOR_EACH_PTR(insn
);
39 static int imbalance(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
, const char *why
)
42 struct symbol
*sym
= ep
->name
;
43 warning(bb
->pos
, "context imbalance in '%s' - %s", show_ident(sym
->ident
), why
);
48 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
);
50 static int check_children(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
52 struct instruction
*insn
;
53 struct basic_block
*child
;
55 insn
= last_instruction(bb
->insns
);
58 if (insn
->opcode
== OP_RET
)
59 return entry
!= exit
? imbalance(ep
, bb
, entry
, exit
, "wrong count at exit") : 0;
61 FOR_EACH_PTR(bb
->children
, child
) {
62 if (check_bb_context(ep
, child
, entry
, exit
))
64 } END_FOR_EACH_PTR(child
);
68 static int check_bb_context(struct entrypoint
*ep
, struct basic_block
*bb
, int entry
, int exit
)
72 if (bb
->context
== entry
)
75 /* Now that's not good.. */
77 return imbalance(ep
, bb
, entry
, bb
->context
, "different lock contexts for basic block");
80 entry
+= context_increase(bb
);
82 return imbalance(ep
, bb
, entry
, exit
, "unexpected unlock");
84 return check_children(ep
, bb
, entry
, exit
);
87 static void check_cast_instruction(struct instruction
*insn
)
89 struct symbol
*orig_type
= insn
->orig_type
;
91 int old
= orig_type
->bit_size
;
93 int oldsigned
= (orig_type
->ctype
.modifiers
& MOD_SIGNED
) != 0;
94 int newsigned
= insn
->opcode
== OP_SCAST
;
97 if (oldsigned
== newsigned
)
101 warning(insn
->pos
, "cast loses sign");
105 warning(insn
->pos
, "cast drops bits");
108 if (oldsigned
== newsigned
) {
109 warning(insn
->pos
, "cast wasn't removed");
112 warning(insn
->pos
, "cast changes sign");
116 static void check_range_instruction(struct instruction
*insn
)
118 warning(insn
->pos
, "value out of range");
121 static void check_byte_count(struct instruction
*insn
, pseudo_t count
)
123 if (count
->type
== PSEUDO_VAL
) {
124 long long val
= count
->value
;
125 if (val
<= 0 || val
> 100000)
126 warning(insn
->pos
, "%s with byte count of %lld",
127 show_ident(insn
->func
->sym
->ident
), val
);
130 /* Ok, we could try to do the range analysis here */
133 static pseudo_t
argument(struct instruction
*call
, unsigned int argno
)
136 struct ptr_list
*arg_list
= (struct ptr_list
*) call
->arguments
;
139 if (linearize_ptr_list(arg_list
, (void *)args
, 8) > argno
)
144 static void check_memset(struct instruction
*insn
)
146 check_byte_count(insn
, argument(insn
, 3));
149 #define check_memcpy check_memset
150 #define check_ctu check_memset
151 #define check_cfu check_memset
155 void (*check
)(struct instruction
*insn
);
158 static void check_call_instruction(struct instruction
*insn
)
160 pseudo_t fn
= insn
->func
;
162 static const struct checkfn check_fn
[] = {
163 { &memset_ident
, check_memset
},
164 { &memcpy_ident
, check_memcpy
},
165 { ©_to_user_ident
, check_ctu
},
166 { ©_from_user_ident
, check_cfu
},
170 if (fn
->type
!= PSEUDO_SYM
)
172 ident
= fn
->sym
->ident
;
175 for (i
= 0; i
< sizeof(check_fn
)/sizeof(struct checkfn
) ; i
++) {
176 if (check_fn
[i
].id
!= ident
)
178 check_fn
[i
].check(insn
);
183 static void check_one_instruction(struct instruction
*insn
)
185 switch (insn
->opcode
) {
186 case OP_CAST
: case OP_SCAST
:
188 check_cast_instruction(insn
);
191 check_range_instruction(insn
);
194 check_call_instruction(insn
);
201 static void check_bb_instructions(struct basic_block
*bb
)
203 struct instruction
*insn
;
204 FOR_EACH_PTR(bb
->insns
, insn
) {
207 check_one_instruction(insn
);
208 } END_FOR_EACH_PTR(insn
);
211 static void check_instructions(struct entrypoint
*ep
)
213 struct basic_block
*bb
;
214 FOR_EACH_PTR(ep
->bbs
, bb
) {
215 check_bb_instructions(bb
);
216 } END_FOR_EACH_PTR(bb
);
219 static void check_context(struct entrypoint
*ep
)
221 struct symbol
*sym
= ep
->name
;
223 if (verbose
&& ep
->entry
->bb
->needs
) {
225 FOR_EACH_PTR(ep
->entry
->bb
->needs
, pseudo
) {
226 if (pseudo
->type
!= PSEUDO_ARG
)
227 warning(sym
->pos
, "%s: possible uninitialized variable (%s)",
228 show_ident(sym
->ident
), show_pseudo(pseudo
));
229 } END_FOR_EACH_PTR(pseudo
);
232 check_instructions(ep
);
234 check_bb_context(ep
, ep
->entry
->bb
, sym
->ctype
.in_context
, sym
->ctype
.out_context
);
237 static void check_symbols(struct symbol_list
*list
)
241 FOR_EACH_PTR(list
, sym
) {
242 struct entrypoint
*ep
;
245 ep
= linearize_symbol(sym
);
248 } END_FOR_EACH_PTR(sym
);
251 int main(int argc
, char **argv
)
253 // Expand, linearize and show it.
254 check_symbols(sparse(argc
, argv
));