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 void check_memset(struct instruction
*insn
)
168 check_byte_count(insn
, ptr_list_nth(insn
->arguments
, 2));
171 #define check_memcpy check_memset
172 #define check_ctu check_memset
173 #define check_cfu check_memset
177 void (*check
)(struct instruction
*insn
);
180 static void check_call_instruction(struct instruction
*insn
)
182 pseudo_t fn
= insn
->func
;
184 static const struct checkfn check_fn
[] = {
185 { &memset_ident
, check_memset
},
186 { &memcpy_ident
, check_memcpy
},
187 { ©_to_user_ident
, check_ctu
},
188 { ©_from_user_ident
, check_cfu
},
192 if (fn
->type
!= PSEUDO_SYM
)
194 ident
= fn
->sym
->ident
;
197 for (i
= 0; i
< ARRAY_SIZE(check_fn
); i
++) {
198 if (check_fn
[i
].id
!= ident
)
200 check_fn
[i
].check(insn
);
205 static void check_one_instruction(struct instruction
*insn
)
207 switch (insn
->opcode
) {
208 case OP_SEXT
: case OP_ZEXT
:
211 check_cast_instruction(insn
);
214 check_range_instruction(insn
);
217 check_call_instruction(insn
);
224 static void check_bb_instructions(struct basic_block
*bb
)
226 struct instruction
*insn
;
227 FOR_EACH_PTR(bb
->insns
, insn
) {
230 check_one_instruction(insn
);
231 } END_FOR_EACH_PTR(insn
);
234 static void check_instructions(struct entrypoint
*ep
)
236 struct basic_block
*bb
;
237 FOR_EACH_PTR(ep
->bbs
, bb
) {
239 check_bb_instructions(bb
);
240 } END_FOR_EACH_PTR(bb
);
243 static void check_context(struct entrypoint
*ep
)
245 struct symbol
*sym
= ep
->name
;
246 struct context
*context
;
247 unsigned int in_context
= 0, out_context
= 0;
249 if (Wuninitialized
&& verbose
&& ep
->entry
->bb
->needs
) {
251 FOR_EACH_PTR(ep
->entry
->bb
->needs
, pseudo
) {
252 if (pseudo
->type
!= PSEUDO_ARG
)
253 warning(sym
->pos
, "%s: possible uninitialized variable (%s)",
254 show_ident(sym
->ident
), show_pseudo(pseudo
));
255 } END_FOR_EACH_PTR(pseudo
);
258 check_instructions(ep
);
260 FOR_EACH_PTR(sym
->ctype
.contexts
, context
) {
261 in_context
+= context
->in
;
262 out_context
+= context
->out
;
263 } END_FOR_EACH_PTR(context
);
264 check_bb_context(ep
, ep
->entry
->bb
, in_context
, out_context
);
267 /* list_compound_symbol - symbol info for arrays, structures, unions */
268 static void list_compound_symbol(struct symbol
*sym
)
272 /* Only show symbols that have a positive size */
273 if (sym
->bit_size
<= 0)
275 if (!sym
->ctype
.base_type
)
277 /* Don't show unnamed types */
281 if (sym
->type
== SYM_NODE
)
282 base
= sym
->ctype
.base_type
;
285 switch (base
->type
) {
286 case SYM_STRUCT
: case SYM_UNION
: case SYM_ARRAY
:
292 info(sym
->pos
, "%s: compound size %u, alignment %lu",
294 bits_to_bytes(sym
->bit_size
),
295 sym
->ctype
.alignment
);
298 static void check_symbols(struct symbol_list
*list
)
302 FOR_EACH_PTR(list
, sym
) {
303 struct entrypoint
*ep
;
306 ep
= linearize_symbol(sym
);
307 if (ep
&& ep
->entry
) {
314 list_compound_symbol(sym
);
315 } END_FOR_EACH_PTR(sym
);
317 if (Wsparse_error
&& die_if_error
)
321 int main(int argc
, char **argv
)
323 struct string_list
*filelist
= NULL
;
326 // by default ignore -o <file>
329 // Expand, linearize and show it.
330 check_symbols(sparse_initialize(argc
, argv
, &filelist
));
331 FOR_EACH_PTR(filelist
, file
) {
332 check_symbols(sparse(file
));
333 } END_FOR_EACH_PTR(file
);