/* * Copyright 2023 Linaro Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt */ #include "smatch.h" #include "smatch_slist.h" #include "smatch_extra.h" static int my_id; static struct statement *get_if_statement(struct expression *expr) { struct statement *stmt, *parent; struct expression *tmp; int count = 0; stmt = get_parent_stmt(expr); if (!stmt) return NULL; stmt = stmt_get_parent_stmt(stmt); while (stmt && stmt->pos.line == expr->pos.line && stmt->pos.pos == expr->pos.pos) { if (count++ >= 5) break; parent = stmt_get_parent_stmt(stmt); if (!parent) { tmp = stmt_get_parent_expr(stmt); parent = get_parent_stmt(tmp); } stmt = parent; } if (!stmt) return NULL; if (stmt->type == STMT_COMPOUND) stmt = stmt_get_parent_stmt(stmt); if (!stmt || stmt->type != STMT_IF) return NULL; return stmt; } static struct expression *get_condition_var(struct expression *expr) { expr = strip_expr(expr); if (expr->type == EXPR_COMPARE && (expr->op == SPECIAL_NOTEQUAL || expr->op == '<') && expr_is_zero(expr->right)) return expr->left; return expr; } static void match_warn(const char *fn, struct expression *expr, void *_unused) { struct statement *stmt; struct expression *var; stmt = get_if_statement(expr); if (!stmt) return; var = get_condition_var(stmt->if_conditional); if (!is_EPROBE_DEFER(var)) return; sm_msg("EPROBE_DEFER path should not print warnings"); } void check_eprobe_defer_is_silent(int id) { const char *warn_fn[] = { "_dev_emerg", "_dev_crit", "_dev_alert", "_dev_err", "_dev_warn", "_dev_notice", "printk", "_printk"}; int i; my_id = id; if (option_project != PROJ_KERNEL) return; for (i = 0; i < ARRAY_SIZE(warn_fn); i++) add_function_hook(warn_fn[i], &match_warn, NULL); }