modification_hooks: use modification info from the database
authorDan Carpenter <dan.carpenter@oracle.com>
Mon, 28 Jan 2013 06:49:57 +0000 (28 09:49 +0300)
committerDan Carpenter <dan.carpenter@oracle.com>
Mon, 28 Jan 2013 06:49:57 +0000 (28 09:49 +0300)
Add a db callback for when the data is modified.

This isn't beautiful.

Eventually I think I'd like to get rid of modification_hooks.  It sort of
duplicates the work done in smatch_extra.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch_modification_hooks.c

index 5818a38..7c1c6f7 100644 (file)
@@ -91,6 +91,69 @@ free:
        free_string(name);
 }
 
+static char *get_variable_from_key(struct expression *arg, char *key, struct symbol **sym)
+{
+       char buf[256];
+       char *tmp;
+
+       if (strcmp(key, "$$") == 0)
+               return expr_to_var_sym(arg, sym);
+
+       if (strcmp(key, "*$$") == 0) {
+               if (arg->type == EXPR_PREOP && arg->op == '&') {
+                       arg = strip_expr(arg->unop);
+                       return expr_to_var_sym(arg, sym);
+               } else {
+                       tmp = expr_to_var_sym(arg, sym);
+                       if (!tmp)
+                               return NULL;
+                       snprintf(buf, sizeof(buf), "*%s", tmp);
+                       free_string(tmp);
+                       return alloc_string(buf);
+               }
+       }
+
+       if (arg->type == EXPR_PREOP && arg->op == '&') {
+               arg = strip_expr(arg->unop);
+               tmp = expr_to_var_sym(arg, sym);
+               if (!tmp)
+                       return NULL;
+               snprintf(buf, sizeof(buf), "%s.%s", tmp, key + 4);
+               return alloc_string(buf);
+       }
+
+       tmp = expr_to_var_sym(arg, sym);
+       if (!tmp)
+               return NULL;
+       snprintf(buf, sizeof(buf), "%s%s", tmp, key + 2);
+       free_string(tmp);
+       return alloc_string(buf);
+}
+
+static void db_param_add(struct expression *expr, int param, char *key, char *value)
+{
+       struct expression *arg;
+       char *name;
+       struct symbol *sym;
+
+       while (expr->type == EXPR_ASSIGNMENT)
+               expr = strip_expr(expr->right);
+       if (expr->type != EXPR_CALL)
+               return;
+
+       arg = get_argument_from_call_expr(expr->args, param);
+       if (!arg)
+               return;
+
+       name = get_variable_from_key(arg, key, &sym);
+       if (!name || !sym)
+               goto free;
+
+       call_modification_hooks_name_sym(name, sym);
+free:
+       free_string(name);
+}
+
 static void match_assign(struct expression *expr)
 {
        call_modification_hooks(expr->left);
@@ -155,5 +218,6 @@ void register_modification_hooks(int id)
 void register_modification_hooks_late(int id)
 {
        add_hook(&match_call, FUNCTION_CALL_HOOK);
+       add_db_return_states_callback(ADDED_VALUE, &db_param_add);
 }