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
)
136 if (count
->type
== PSEUDO_VAL
) {
137 long long val
= count
->value
;
138 if (val
<= 0 || val
> 100000)
139 warning(insn
->pos
, "%s with byte count of %lld",
140 show_ident(insn
->func
->sym
->ident
), val
);
143 /* Ok, we could try to do the range analysis here */
146 static pseudo_t
argument(struct instruction
*call
, unsigned int argno
)
149 struct ptr_list
*arg_list
= (struct ptr_list
*) call
->arguments
;
152 if (linearize_ptr_list(arg_list
, (void *)args
, 8) > argno
)
157 static void check_memset(struct instruction
*insn
)
159 check_byte_count(insn
, argument(insn
, 3));
162 #define check_memcpy check_memset
163 #define check_ctu check_memset
164 #define check_cfu check_memset
168 void (*check
)(struct instruction
*insn
);
171 static void check_call_instruction(struct instruction
*insn
)
173 pseudo_t fn
= insn
->func
;
175 static const struct checkfn check_fn
[] = {
176 { &memset_ident
, check_memset
},
177 { &memcpy_ident
, check_memcpy
},
178 { ©_to_user_ident
, check_ctu
},
179 { ©_from_user_ident
, check_cfu
},
183 if (fn
->type
!= PSEUDO_SYM
)
185 ident
= fn
->sym
->ident
;
188 for (i
= 0; i
< sizeof(check_fn
)/sizeof(struct checkfn
) ; i
++) {
189 if (check_fn
[i
].id
!= ident
)
191 check_fn
[i
].check(insn
);
196 static void check_one_instruction(struct instruction
*insn
)
198 switch (insn
->opcode
) {
199 case OP_CAST
: case OP_SCAST
:
201 check_cast_instruction(insn
);
204 check_range_instruction(insn
);
207 check_call_instruction(insn
);
214 static void check_bb_instructions(struct basic_block
*bb
)
216 struct instruction
*insn
;
217 FOR_EACH_PTR(bb
->insns
, insn
) {
220 check_one_instruction(insn
);
221 } END_FOR_EACH_PTR(insn
);
224 static void check_instructions(struct entrypoint
*ep
)
226 struct basic_block
*bb
;
227 FOR_EACH_PTR(ep
->bbs
, bb
) {
228 check_bb_instructions(bb
);
229 } END_FOR_EACH_PTR(bb
);
232 static void check_context(struct entrypoint
*ep
)
234 struct symbol
*sym
= ep
->name
;
236 if (verbose
&& ep
->entry
->bb
->needs
) {
238 FOR_EACH_PTR(ep
->entry
->bb
->needs
, pseudo
) {
239 if (pseudo
->type
!= PSEUDO_ARG
)
240 warning(sym
->pos
, "%s: possible uninitialized variable (%s)",
241 show_ident(sym
->ident
), show_pseudo(pseudo
));
242 } END_FOR_EACH_PTR(pseudo
);
245 check_instructions(ep
);
247 check_bb_context(ep
, ep
->entry
->bb
, sym
->ctype
.in_context
, sym
->ctype
.out_context
);
250 static void check_symbols(struct symbol_list
*list
)
254 FOR_EACH_PTR(list
, sym
) {
255 struct entrypoint
*ep
;
258 ep
= linearize_symbol(sym
);
261 } END_FOR_EACH_PTR(sym
);
264 int main(int argc
, char **argv
)
266 // Expand, linearize and show it.
267 check_symbols(sparse(argc
, argv
));