1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Example trivial client program that uses the sparse library 3f08c3bdfSopenharmony_ci * to tokenize, preprocess and parse a C file, and prints out 4f08c3bdfSopenharmony_ci * the results. 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Copyright (C) 2003 Transmeta Corp. 7f08c3bdfSopenharmony_ci * 2003-2004 Linus Torvalds 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 10f08c3bdfSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 11f08c3bdfSopenharmony_ci * in the Software without restriction, including without limitation the rights 12f08c3bdfSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13f08c3bdfSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 14f08c3bdfSopenharmony_ci * furnished to do so, subject to the following conditions: 15f08c3bdfSopenharmony_ci * 16f08c3bdfSopenharmony_ci * The above copyright notice and this permission notice shall be included in 17f08c3bdfSopenharmony_ci * all copies or substantial portions of the Software. 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20f08c3bdfSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21f08c3bdfSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22f08c3bdfSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23f08c3bdfSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24f08c3bdfSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25f08c3bdfSopenharmony_ci * THE SOFTWARE. 26f08c3bdfSopenharmony_ci */ 27f08c3bdfSopenharmony_ci#include <stdarg.h> 28f08c3bdfSopenharmony_ci#include <stdlib.h> 29f08c3bdfSopenharmony_ci#include <stdio.h> 30f08c3bdfSopenharmony_ci#include <string.h> 31f08c3bdfSopenharmony_ci#include <ctype.h> 32f08c3bdfSopenharmony_ci#include <unistd.h> 33f08c3bdfSopenharmony_ci#include <fcntl.h> 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci#include "lib.h" 36f08c3bdfSopenharmony_ci#include "allocate.h" 37f08c3bdfSopenharmony_ci#include "token.h" 38f08c3bdfSopenharmony_ci#include "parse.h" 39f08c3bdfSopenharmony_ci#include "symbol.h" 40f08c3bdfSopenharmony_ci#include "expression.h" 41f08c3bdfSopenharmony_ci#include "linearize.h" 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_cistatic int context_increase(struct basic_block *bb, int entry) 44f08c3bdfSopenharmony_ci{ 45f08c3bdfSopenharmony_ci int sum = 0; 46f08c3bdfSopenharmony_ci struct instruction *insn; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci FOR_EACH_PTR(bb->insns, insn) { 49f08c3bdfSopenharmony_ci int val; 50f08c3bdfSopenharmony_ci if (!insn->bb) 51f08c3bdfSopenharmony_ci continue; 52f08c3bdfSopenharmony_ci if (insn->opcode != OP_CONTEXT) 53f08c3bdfSopenharmony_ci continue; 54f08c3bdfSopenharmony_ci val = insn->increment; 55f08c3bdfSopenharmony_ci if (insn->check) { 56f08c3bdfSopenharmony_ci int current = sum + entry; 57f08c3bdfSopenharmony_ci if (!val) { 58f08c3bdfSopenharmony_ci if (!current) 59f08c3bdfSopenharmony_ci continue; 60f08c3bdfSopenharmony_ci } else if (current >= val) 61f08c3bdfSopenharmony_ci continue; 62f08c3bdfSopenharmony_ci warning(insn->pos, "context check failure"); 63f08c3bdfSopenharmony_ci continue; 64f08c3bdfSopenharmony_ci } 65f08c3bdfSopenharmony_ci sum += val; 66f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(insn); 67f08c3bdfSopenharmony_ci return sum; 68f08c3bdfSopenharmony_ci} 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_cistatic int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why) 71f08c3bdfSopenharmony_ci{ 72f08c3bdfSopenharmony_ci if (Wcontext) { 73f08c3bdfSopenharmony_ci struct symbol *sym = ep->name; 74f08c3bdfSopenharmony_ci warning(bb->pos, "context imbalance in '%s' - %s", show_ident(sym->ident), why); 75f08c3bdfSopenharmony_ci } 76f08c3bdfSopenharmony_ci return -1; 77f08c3bdfSopenharmony_ci} 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_cistatic int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_cistatic int check_children(struct entrypoint *ep, struct basic_block *bb, int entry, int exit) 82f08c3bdfSopenharmony_ci{ 83f08c3bdfSopenharmony_ci struct instruction *insn; 84f08c3bdfSopenharmony_ci struct basic_block *child; 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci insn = last_instruction(bb->insns); 87f08c3bdfSopenharmony_ci if (!insn) 88f08c3bdfSopenharmony_ci return 0; 89f08c3bdfSopenharmony_ci if (insn->opcode == OP_RET) 90f08c3bdfSopenharmony_ci return entry != exit ? imbalance(ep, bb, entry, exit, "wrong count at exit") : 0; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci FOR_EACH_PTR(bb->children, child) { 93f08c3bdfSopenharmony_ci if (check_bb_context(ep, child, entry, exit)) 94f08c3bdfSopenharmony_ci return -1; 95f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(child); 96f08c3bdfSopenharmony_ci return 0; 97f08c3bdfSopenharmony_ci} 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistatic int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit) 100f08c3bdfSopenharmony_ci{ 101f08c3bdfSopenharmony_ci if (!bb) 102f08c3bdfSopenharmony_ci return 0; 103f08c3bdfSopenharmony_ci if (bb->context == entry) 104f08c3bdfSopenharmony_ci return 0; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci /* Now that's not good.. */ 107f08c3bdfSopenharmony_ci if (bb->context >= 0) 108f08c3bdfSopenharmony_ci return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block"); 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci bb->context = entry; 111f08c3bdfSopenharmony_ci entry += context_increase(bb, entry); 112f08c3bdfSopenharmony_ci if (entry < 0) 113f08c3bdfSopenharmony_ci return imbalance(ep, bb, entry, exit, "unexpected unlock"); 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci return check_children(ep, bb, entry, exit); 116f08c3bdfSopenharmony_ci} 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_cistatic void check_cast_instruction(struct instruction *insn) 119f08c3bdfSopenharmony_ci{ 120f08c3bdfSopenharmony_ci struct symbol *orig_type = insn->orig_type; 121f08c3bdfSopenharmony_ci if (orig_type) { 122f08c3bdfSopenharmony_ci int old = orig_type->bit_size; 123f08c3bdfSopenharmony_ci int new = insn->size; 124f08c3bdfSopenharmony_ci int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0; 125f08c3bdfSopenharmony_ci int newsigned = insn->opcode == OP_SEXT; 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci if (new > old) { 128f08c3bdfSopenharmony_ci if (oldsigned == newsigned) 129f08c3bdfSopenharmony_ci return; 130f08c3bdfSopenharmony_ci if (newsigned) 131f08c3bdfSopenharmony_ci return; 132f08c3bdfSopenharmony_ci warning(insn->pos, "cast loses sign"); 133f08c3bdfSopenharmony_ci return; 134f08c3bdfSopenharmony_ci } 135f08c3bdfSopenharmony_ci if (new < old) { 136f08c3bdfSopenharmony_ci warning(insn->pos, "cast drops bits"); 137f08c3bdfSopenharmony_ci return; 138f08c3bdfSopenharmony_ci } 139f08c3bdfSopenharmony_ci if (oldsigned == newsigned) { 140f08c3bdfSopenharmony_ci warning(insn->pos, "cast wasn't removed"); 141f08c3bdfSopenharmony_ci return; 142f08c3bdfSopenharmony_ci } 143f08c3bdfSopenharmony_ci warning(insn->pos, "cast changes sign"); 144f08c3bdfSopenharmony_ci } 145f08c3bdfSopenharmony_ci} 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_cistatic void check_range_instruction(struct instruction *insn) 148f08c3bdfSopenharmony_ci{ 149f08c3bdfSopenharmony_ci warning(insn->pos, "value out of range"); 150f08c3bdfSopenharmony_ci} 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_cistatic void check_byte_count(struct instruction *insn, pseudo_t count) 153f08c3bdfSopenharmony_ci{ 154f08c3bdfSopenharmony_ci if (!count) 155f08c3bdfSopenharmony_ci return; 156f08c3bdfSopenharmony_ci if (count->type == PSEUDO_VAL) { 157f08c3bdfSopenharmony_ci unsigned long long val = count->value; 158f08c3bdfSopenharmony_ci if (Wmemcpy_max_count && val > fmemcpy_max_count) 159f08c3bdfSopenharmony_ci warning(insn->pos, "%s with byte count of %llu", 160f08c3bdfSopenharmony_ci show_ident(insn->func->sym->ident), val); 161f08c3bdfSopenharmony_ci return; 162f08c3bdfSopenharmony_ci } 163f08c3bdfSopenharmony_ci /* OK, we could try to do the range analysis here */ 164f08c3bdfSopenharmony_ci} 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_cistatic void check_memset(struct instruction *insn) 167f08c3bdfSopenharmony_ci{ 168f08c3bdfSopenharmony_ci check_byte_count(insn, ptr_list_nth(insn->arguments, 3)); 169f08c3bdfSopenharmony_ci} 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci#define check_memcpy check_memset 172f08c3bdfSopenharmony_ci#define check_ctu check_memset 173f08c3bdfSopenharmony_ci#define check_cfu check_memset 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_cistruct checkfn { 176f08c3bdfSopenharmony_ci struct ident *id; 177f08c3bdfSopenharmony_ci void (*check)(struct instruction *insn); 178f08c3bdfSopenharmony_ci}; 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_cistatic void check_call_instruction(struct instruction *insn) 181f08c3bdfSopenharmony_ci{ 182f08c3bdfSopenharmony_ci pseudo_t fn = insn->func; 183f08c3bdfSopenharmony_ci struct ident *ident; 184f08c3bdfSopenharmony_ci static const struct checkfn check_fn[] = { 185f08c3bdfSopenharmony_ci { &memset_ident, check_memset }, 186f08c3bdfSopenharmony_ci { &memcpy_ident, check_memcpy }, 187f08c3bdfSopenharmony_ci { ©_to_user_ident, check_ctu }, 188f08c3bdfSopenharmony_ci { ©_from_user_ident, check_cfu }, 189f08c3bdfSopenharmony_ci }; 190f08c3bdfSopenharmony_ci int i; 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci if (fn->type != PSEUDO_SYM) 193f08c3bdfSopenharmony_ci return; 194f08c3bdfSopenharmony_ci ident = fn->sym->ident; 195f08c3bdfSopenharmony_ci if (!ident) 196f08c3bdfSopenharmony_ci return; 197f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(check_fn); i++) { 198f08c3bdfSopenharmony_ci if (check_fn[i].id != ident) 199f08c3bdfSopenharmony_ci continue; 200f08c3bdfSopenharmony_ci check_fn[i].check(insn); 201f08c3bdfSopenharmony_ci break; 202f08c3bdfSopenharmony_ci } 203f08c3bdfSopenharmony_ci} 204f08c3bdfSopenharmony_ci 205f08c3bdfSopenharmony_cistatic void check_one_instruction(struct instruction *insn) 206f08c3bdfSopenharmony_ci{ 207f08c3bdfSopenharmony_ci switch (insn->opcode) { 208f08c3bdfSopenharmony_ci case OP_SEXT: case OP_ZEXT: 209f08c3bdfSopenharmony_ci case OP_TRUNC: 210f08c3bdfSopenharmony_ci if (verbose) 211f08c3bdfSopenharmony_ci check_cast_instruction(insn); 212f08c3bdfSopenharmony_ci break; 213f08c3bdfSopenharmony_ci case OP_RANGE: 214f08c3bdfSopenharmony_ci check_range_instruction(insn); 215f08c3bdfSopenharmony_ci break; 216f08c3bdfSopenharmony_ci case OP_CALL: 217f08c3bdfSopenharmony_ci check_call_instruction(insn); 218f08c3bdfSopenharmony_ci break; 219f08c3bdfSopenharmony_ci default: 220f08c3bdfSopenharmony_ci break; 221f08c3bdfSopenharmony_ci } 222f08c3bdfSopenharmony_ci} 223f08c3bdfSopenharmony_ci 224f08c3bdfSopenharmony_cistatic void check_bb_instructions(struct basic_block *bb) 225f08c3bdfSopenharmony_ci{ 226f08c3bdfSopenharmony_ci struct instruction *insn; 227f08c3bdfSopenharmony_ci FOR_EACH_PTR(bb->insns, insn) { 228f08c3bdfSopenharmony_ci if (!insn->bb) 229f08c3bdfSopenharmony_ci continue; 230f08c3bdfSopenharmony_ci check_one_instruction(insn); 231f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(insn); 232f08c3bdfSopenharmony_ci} 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_cistatic void check_instructions(struct entrypoint *ep) 235f08c3bdfSopenharmony_ci{ 236f08c3bdfSopenharmony_ci struct basic_block *bb; 237f08c3bdfSopenharmony_ci FOR_EACH_PTR(ep->bbs, bb) { 238f08c3bdfSopenharmony_ci bb->context = -1; 239f08c3bdfSopenharmony_ci check_bb_instructions(bb); 240f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(bb); 241f08c3bdfSopenharmony_ci} 242f08c3bdfSopenharmony_ci 243f08c3bdfSopenharmony_cistatic void check_context(struct entrypoint *ep) 244f08c3bdfSopenharmony_ci{ 245f08c3bdfSopenharmony_ci struct symbol *sym = ep->name; 246f08c3bdfSopenharmony_ci struct context *context; 247f08c3bdfSopenharmony_ci unsigned int in_context = 0, out_context = 0; 248f08c3bdfSopenharmony_ci 249f08c3bdfSopenharmony_ci if (Wuninitialized && verbose && ep->entry->bb->needs) { 250f08c3bdfSopenharmony_ci pseudo_t pseudo; 251f08c3bdfSopenharmony_ci FOR_EACH_PTR(ep->entry->bb->needs, pseudo) { 252f08c3bdfSopenharmony_ci if (pseudo->type != PSEUDO_ARG) 253f08c3bdfSopenharmony_ci warning(sym->pos, "%s: possible uninitialized variable (%s)", 254f08c3bdfSopenharmony_ci show_ident(sym->ident), show_pseudo(pseudo)); 255f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(pseudo); 256f08c3bdfSopenharmony_ci } 257f08c3bdfSopenharmony_ci 258f08c3bdfSopenharmony_ci check_instructions(ep); 259f08c3bdfSopenharmony_ci 260f08c3bdfSopenharmony_ci FOR_EACH_PTR(sym->ctype.contexts, context) { 261f08c3bdfSopenharmony_ci in_context += context->in; 262f08c3bdfSopenharmony_ci out_context += context->out; 263f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(context); 264f08c3bdfSopenharmony_ci check_bb_context(ep, ep->entry->bb, in_context, out_context); 265f08c3bdfSopenharmony_ci} 266f08c3bdfSopenharmony_ci 267f08c3bdfSopenharmony_ci/* list_compound_symbol - symbol info for arrays, structures, unions */ 268f08c3bdfSopenharmony_cistatic void list_compound_symbol(struct symbol *sym) 269f08c3bdfSopenharmony_ci{ 270f08c3bdfSopenharmony_ci struct symbol *base; 271f08c3bdfSopenharmony_ci 272f08c3bdfSopenharmony_ci /* Only show symbols that have a positive size */ 273f08c3bdfSopenharmony_ci if (sym->bit_size <= 0) 274f08c3bdfSopenharmony_ci return; 275f08c3bdfSopenharmony_ci if (!sym->ctype.base_type) 276f08c3bdfSopenharmony_ci return; 277f08c3bdfSopenharmony_ci /* Don't show unnamed types */ 278f08c3bdfSopenharmony_ci if (!sym->ident) 279f08c3bdfSopenharmony_ci return; 280f08c3bdfSopenharmony_ci 281f08c3bdfSopenharmony_ci if (sym->type == SYM_NODE) 282f08c3bdfSopenharmony_ci base = sym->ctype.base_type; 283f08c3bdfSopenharmony_ci else 284f08c3bdfSopenharmony_ci base = sym; 285f08c3bdfSopenharmony_ci switch (base->type) { 286f08c3bdfSopenharmony_ci case SYM_STRUCT: case SYM_UNION: case SYM_ARRAY: 287f08c3bdfSopenharmony_ci break; 288f08c3bdfSopenharmony_ci default: 289f08c3bdfSopenharmony_ci return; 290f08c3bdfSopenharmony_ci } 291f08c3bdfSopenharmony_ci 292f08c3bdfSopenharmony_ci info(sym->pos, "%s: compound size %u, alignment %lu", 293f08c3bdfSopenharmony_ci show_typename(sym), 294f08c3bdfSopenharmony_ci bits_to_bytes(sym->bit_size), 295f08c3bdfSopenharmony_ci sym->ctype.alignment); 296f08c3bdfSopenharmony_ci} 297f08c3bdfSopenharmony_ci 298f08c3bdfSopenharmony_cistatic void check_symbols(struct symbol_list *list) 299f08c3bdfSopenharmony_ci{ 300f08c3bdfSopenharmony_ci struct symbol *sym; 301f08c3bdfSopenharmony_ci 302f08c3bdfSopenharmony_ci FOR_EACH_PTR(list, sym) { 303f08c3bdfSopenharmony_ci struct entrypoint *ep; 304f08c3bdfSopenharmony_ci 305f08c3bdfSopenharmony_ci expand_symbol(sym); 306f08c3bdfSopenharmony_ci ep = linearize_symbol(sym); 307f08c3bdfSopenharmony_ci if (ep && ep->entry) { 308f08c3bdfSopenharmony_ci if (dbg_entry) 309f08c3bdfSopenharmony_ci show_entry(ep); 310f08c3bdfSopenharmony_ci 311f08c3bdfSopenharmony_ci check_context(ep); 312f08c3bdfSopenharmony_ci } 313f08c3bdfSopenharmony_ci if (dbg_compound) 314f08c3bdfSopenharmony_ci list_compound_symbol(sym); 315f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(sym); 316f08c3bdfSopenharmony_ci 317f08c3bdfSopenharmony_ci if (Wsparse_error && die_if_error) 318f08c3bdfSopenharmony_ci exit(1); 319f08c3bdfSopenharmony_ci} 320f08c3bdfSopenharmony_ci 321f08c3bdfSopenharmony_ciint main(int argc, char **argv) 322f08c3bdfSopenharmony_ci{ 323f08c3bdfSopenharmony_ci struct string_list *filelist = NULL; 324f08c3bdfSopenharmony_ci char *file; 325f08c3bdfSopenharmony_ci 326f08c3bdfSopenharmony_ci // by default ignore -o <file> 327f08c3bdfSopenharmony_ci do_output = 0; 328f08c3bdfSopenharmony_ci 329f08c3bdfSopenharmony_ci // Expand, linearize and show it. 330f08c3bdfSopenharmony_ci check_symbols(sparse_initialize(argc, argv, &filelist)); 331f08c3bdfSopenharmony_ci FOR_EACH_PTR(filelist, file) { 332f08c3bdfSopenharmony_ci check_symbols(sparse(file)); 333f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(file); 334f08c3bdfSopenharmony_ci 335f08c3bdfSopenharmony_ci report_stats(); 336f08c3bdfSopenharmony_ci return 0; 337f08c3bdfSopenharmony_ci} 338