30 #include <string.h>
31 #include <ctype.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34
35 #include "lib.h"
36 #include "allocate.h"
37 #include "token.h"
38 #include "parse.h"
39 #include "symbol.h"
40 #include "expression.h"
41 #include "linearize.h"
42
43 static int context_increase(struct basic_block *bb, int entry)
44 {
45 int sum = 0;
46 struct instruction *insn;
47
48 FOR_EACH_PTR(bb->insns, insn) {
49 int val;
50 if (insn->opcode != OP_CONTEXT)
51 continue;
52 val = insn->increment;
53 if (insn->check) {
54 int current = sum + entry;
55 if (!val) {
56 if (!current)
57 continue;
58 } else if (current >= val)
59 continue;
60 warning(insn->pos, "context check failure");
61 continue;
62 }
63 sum += val;
64 } END_FOR_EACH_PTR(insn);
65 return sum;
66 }
67
68 static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
69 {
103
104 /* Now that's not good.. */
105 if (bb->context >= 0)
106 return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block");
107
108 bb->context = entry;
109 entry += context_increase(bb, entry);
110 if (entry < 0)
111 return imbalance(ep, bb, entry, exit, "unexpected unlock");
112
113 return check_children(ep, bb, entry, exit);
114 }
115
116 static void check_cast_instruction(struct instruction *insn)
117 {
118 struct symbol *orig_type = insn->orig_type;
119 if (orig_type) {
120 int old = orig_type->bit_size;
121 int new = insn->size;
122 int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
123 int newsigned = insn->opcode == OP_SCAST;
124
125 if (new > old) {
126 if (oldsigned == newsigned)
127 return;
128 if (newsigned)
129 return;
130 warning(insn->pos, "cast loses sign");
131 return;
132 }
133 if (new < old) {
134 warning(insn->pos, "cast drops bits");
135 return;
136 }
137 if (oldsigned == newsigned) {
138 warning(insn->pos, "cast wasn't removed");
139 return;
140 }
141 warning(insn->pos, "cast changes sign");
142 }
143 }
197 { ©_from_user_ident, check_cfu },
198 };
199 int i;
200
201 if (fn->type != PSEUDO_SYM)
202 return;
203 ident = fn->sym->ident;
204 if (!ident)
205 return;
206 for (i = 0; i < ARRAY_SIZE(check_fn); i++) {
207 if (check_fn[i].id != ident)
208 continue;
209 check_fn[i].check(insn);
210 break;
211 }
212 }
213
214 static void check_one_instruction(struct instruction *insn)
215 {
216 switch (insn->opcode) {
217 case OP_CAST: case OP_SCAST:
218 if (verbose)
219 check_cast_instruction(insn);
220 break;
221 case OP_RANGE:
222 check_range_instruction(insn);
223 break;
224 case OP_CALL:
225 check_call_instruction(insn);
226 break;
227 default:
228 break;
229 }
230 }
231
232 static void check_bb_instructions(struct basic_block *bb)
233 {
234 struct instruction *insn;
235 FOR_EACH_PTR(bb->insns, insn) {
236 if (!insn->bb)
237 continue;
238 check_one_instruction(insn);
239 } END_FOR_EACH_PTR(insn);
240 }
241
242 static void check_instructions(struct entrypoint *ep)
243 {
244 struct basic_block *bb;
245 FOR_EACH_PTR(ep->bbs, bb) {
246 check_bb_instructions(bb);
247 } END_FOR_EACH_PTR(bb);
248 }
249
250 static void check_context(struct entrypoint *ep)
251 {
252 struct symbol *sym = ep->name;
253 struct context *context;
254 unsigned int in_context = 0, out_context = 0;
255
256 if (Wuninitialized && verbose && ep->entry->bb->needs) {
257 pseudo_t pseudo;
258 FOR_EACH_PTR(ep->entry->bb->needs, pseudo) {
259 if (pseudo->type != PSEUDO_ARG)
260 warning(sym->pos, "%s: possible uninitialized variable (%s)",
261 show_ident(sym->ident), show_pseudo(pseudo));
262 } END_FOR_EACH_PTR(pseudo);
263 }
264
265 check_instructions(ep);
266
267 FOR_EACH_PTR(sym->ctype.contexts, context) {
268 in_context += context->in;
269 out_context += context->out;
270 } END_FOR_EACH_PTR(context);
271 check_bb_context(ep, ep->entry->bb, in_context, out_context);
272 }
273
274 static void check_symbols(struct symbol_list *list)
275 {
276 struct symbol *sym;
277
278 FOR_EACH_PTR(list, sym) {
279 struct entrypoint *ep;
280
281 expand_symbol(sym);
282 ep = linearize_symbol(sym);
283 if (ep) {
284 if (dbg_entry)
285 show_entry(ep);
286
287 check_context(ep);
288 }
289 } END_FOR_EACH_PTR(sym);
290
291 if (Wsparse_error && die_if_error)
292 exit(1);
293 }
294
295 int main(int argc, char **argv)
296 {
297 struct string_list *filelist = NULL;
298 char *file;
299
300 // Expand, linearize and show it.
301 check_symbols(sparse_initialize(argc, argv, &filelist));
302 FOR_EACH_PTR_NOTAG(filelist, file) {
303 check_symbols(sparse(file));
304 } END_FOR_EACH_PTR_NOTAG(file);
305
306 report_stats();
307 return 0;
308 }
|
30 #include <string.h>
31 #include <ctype.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34
35 #include "lib.h"
36 #include "allocate.h"
37 #include "token.h"
38 #include "parse.h"
39 #include "symbol.h"
40 #include "expression.h"
41 #include "linearize.h"
42
43 static int context_increase(struct basic_block *bb, int entry)
44 {
45 int sum = 0;
46 struct instruction *insn;
47
48 FOR_EACH_PTR(bb->insns, insn) {
49 int val;
50 if (!insn->bb)
51 continue;
52 if (insn->opcode != OP_CONTEXT)
53 continue;
54 val = insn->increment;
55 if (insn->check) {
56 int current = sum + entry;
57 if (!val) {
58 if (!current)
59 continue;
60 } else if (current >= val)
61 continue;
62 warning(insn->pos, "context check failure");
63 continue;
64 }
65 sum += val;
66 } END_FOR_EACH_PTR(insn);
67 return sum;
68 }
69
70 static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
71 {
105
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");
109
110 bb->context = entry;
111 entry += context_increase(bb, entry);
112 if (entry < 0)
113 return imbalance(ep, bb, entry, exit, "unexpected unlock");
114
115 return check_children(ep, bb, entry, exit);
116 }
117
118 static void check_cast_instruction(struct instruction *insn)
119 {
120 struct symbol *orig_type = insn->orig_type;
121 if (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;
126
127 if (new > old) {
128 if (oldsigned == newsigned)
129 return;
130 if (newsigned)
131 return;
132 warning(insn->pos, "cast loses sign");
133 return;
134 }
135 if (new < old) {
136 warning(insn->pos, "cast drops bits");
137 return;
138 }
139 if (oldsigned == newsigned) {
140 warning(insn->pos, "cast wasn't removed");
141 return;
142 }
143 warning(insn->pos, "cast changes sign");
144 }
145 }
199 { ©_from_user_ident, check_cfu },
200 };
201 int i;
202
203 if (fn->type != PSEUDO_SYM)
204 return;
205 ident = fn->sym->ident;
206 if (!ident)
207 return;
208 for (i = 0; i < ARRAY_SIZE(check_fn); i++) {
209 if (check_fn[i].id != ident)
210 continue;
211 check_fn[i].check(insn);
212 break;
213 }
214 }
215
216 static void check_one_instruction(struct instruction *insn)
217 {
218 switch (insn->opcode) {
219 case OP_SEXT: case OP_ZEXT:
220 case OP_TRUNC:
221 if (verbose)
222 check_cast_instruction(insn);
223 break;
224 case OP_RANGE:
225 check_range_instruction(insn);
226 break;
227 case OP_CALL:
228 check_call_instruction(insn);
229 break;
230 default:
231 break;
232 }
233 }
234
235 static void check_bb_instructions(struct basic_block *bb)
236 {
237 struct instruction *insn;
238 FOR_EACH_PTR(bb->insns, insn) {
239 if (!insn->bb)
240 continue;
241 check_one_instruction(insn);
242 } END_FOR_EACH_PTR(insn);
243 }
244
245 static void check_instructions(struct entrypoint *ep)
246 {
247 struct basic_block *bb;
248 FOR_EACH_PTR(ep->bbs, bb) {
249 bb->context = -1;
250 check_bb_instructions(bb);
251 } END_FOR_EACH_PTR(bb);
252 }
253
254 static void check_context(struct entrypoint *ep)
255 {
256 struct symbol *sym = ep->name;
257 struct context *context;
258 unsigned int in_context = 0, out_context = 0;
259
260 if (Wuninitialized && verbose && ep->entry->bb->needs) {
261 pseudo_t pseudo;
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);
267 }
268
269 check_instructions(ep);
270
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);
276 }
277
278 /* list_compound_symbol - symbol info for arrays, structures, unions */
279 static void list_compound_symbol(struct symbol *sym)
280 {
281 struct symbol *base;
282
283 /* Only show symbols that have a positive size */
284 if (sym->bit_size <= 0)
285 return;
286 if (!sym->ctype.base_type)
287 return;
288 /* Don't show unnamed types */
289 if (!sym->ident)
290 return;
291
292 if (sym->type == SYM_NODE)
293 base = sym->ctype.base_type;
294 else
295 base = sym;
296 switch (base->type) {
297 case SYM_STRUCT: case SYM_UNION: case SYM_ARRAY:
298 break;
299 default:
300 return;
301 }
302
303 info(sym->pos, "%s: compound size %u, alignment %lu",
304 show_typename(sym),
305 bits_to_bytes(sym->bit_size),
306 sym->ctype.alignment);
307 }
308
309 static void check_symbols(struct symbol_list *list)
310 {
311 struct symbol *sym;
312
313 FOR_EACH_PTR(list, sym) {
314 struct entrypoint *ep;
315
316 expand_symbol(sym);
317 ep = linearize_symbol(sym);
318 if (ep && ep->entry) {
319 if (dbg_entry)
320 show_entry(ep);
321
322 check_context(ep);
323 }
324 if (dbg_compound)
325 list_compound_symbol(sym);
326 } END_FOR_EACH_PTR(sym);
327
328 if (Wsparse_error && die_if_error)
329 exit(1);
330 }
331
332 int main(int argc, char **argv)
333 {
334 struct string_list *filelist = NULL;
335 char *file;
336
337 // by default ignore -o <file>
338 do_output = 0;
339
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);
345
346 report_stats();
347 return 0;
348 }
|