Events insert advice to capture bound params.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Mon, 7 Feb 2011 23:03:56 +0000 (18:03 -0500)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Mon, 7 Feb 2011 23:03:56 +0000 (18:03 -0500)
src/tracecut.c

index 3ee84b1aaad9b69585f427278f030c3945880834..f3ccbf1d1333eb35068980843f990bba1fecfd21 100644 (file)
@@ -377,6 +377,60 @@ tc_free_tracecut (struct tc_tracecut *tc)
   free(tc);
 }
 
+/* Add an advice call to the tracecut runtime notifying it that an
+   event occurred and that _tc_capture_*_param() calls will follow
+   to specify the event's params. */
+static void
+insert_begin_event_advice (struct aop_joinpoint *jp,
+                          struct tc_call_symbol *symbol)
+{
+  aop_insert_advice (jp, "_tc_event_begin", symbol->location, AOP_TERM_ARG);
+}
+
+/* Add an advice call to _tc_capture_param for each call binding. */
+static void
+capture_call_bindings (struct aop_joinpoint *jp, struct tc_call_symbol *symbol)
+{
+  struct tc_call_binding *binding;
+
+  for (binding = symbol->binding_list; binding != NULL; binding = binding->next)
+    {
+      struct aop_dynval *param_val;
+      const struct aop_type *param_type;
+
+      if (binding->call_param_index >= 0)
+       param_val = aop_capture_call_param (jp, binding->call_param_index);
+      else
+       param_val = aop_capture_call_return_value (jp);
+
+      param_type = aop_get_dynval_type (param_val);
+
+      if (aop_is_pointer_type (param_type))
+       {
+         aop_cast_to_all_pointer (param_val);
+         aop_insert_advice (jp, "_tc_capture_pointer_param", symbol->location,
+                            AOP_INT_CST (symbol->index),
+                            AOP_INT_CST (binding->param->index),
+                            AOP_DYNVAL (param_val), AOP_TERM_ARG);
+       }
+      else
+       {
+         /* TODO: Provide support for more kinds of data. */
+         aop_assert (0);
+       }
+    }  
+}
+
+/* Add an advice call to the tracecut runtime, notifying it that it
+   has all params and should simulate the event transition. */
+static void
+insert_transition_event_advice (struct aop_joinpoint *jp,
+                               struct tc_call_symbol *symbol)
+{
+  aop_insert_advice (jp, "_tc_event_transition", symbol->location,
+                    AOP_INT_CST (symbol->index), AOP_TERM_ARG);
+}
+
 struct join_on_call_arg {
   struct tc_tracecut *tc;
   struct tc_call_symbol *symbol;
@@ -388,8 +442,39 @@ join_on_call (struct aop_joinpoint *jp, void *callback_arg)
   struct join_on_call_arg *arg = callback_arg;
   struct tc_call_symbol *symbol = arg->symbol;
 
-  aop_insert_advice (jp, "_tc_event_transition", symbol->location,
-                    AOP_INT_CST (symbol->index), AOP_TERM_ARG);
+  /* Unfortunately, the choice of AOP_INSERT_BEFORE or
+     AOP_INSERT_AFTER affects the order that inserted advice functions
+     will execute. */
+  if (symbol->location == AOP_INSERT_BEFORE)
+    {
+      /* For AOP_INSERT_BEFORE, we insert in the normal order. */
+      insert_begin_event_advice (jp, symbol);
+      capture_call_bindings (jp, symbol);
+      insert_transition_event_advice (jp, symbol);
+    }
+  else
+    {
+      /* For AOP_INSERT_AFTER, we insert in the reverse order. */
+      insert_transition_event_advice (jp, symbol);
+      capture_call_bindings (jp, symbol);
+      insert_begin_event_advice (jp, symbol);
+    }
+}
+
+static void
+filter_call_pointcut_by_bindings (struct aop_pointcut *pc,
+                                 struct tc_call_symbol *symbol)
+{
+  struct tc_call_binding *binding;
+
+  for (binding = symbol->binding_list; binding != NULL; binding = binding->next)
+    {
+      if (binding->call_param_index >= 0)
+       aop_filter_call_pc_by_param (pc, binding->call_param_index,
+                                    binding->param->type);
+      else
+       aop_filter_call_pc_by_return_type (pc, binding->param->type);
+    }
 }
 
 static void
@@ -404,6 +489,7 @@ add_instrumentation_for_tracecut (struct tc_tracecut *tc)
 
       pc = aop_match_function_call ();
       aop_filter_call_pc_by_name (pc, symbol->func_name);
+      filter_call_pointcut_by_bindings (pc, symbol);
 
       arg.tc = tc;
       arg.symbol = symbol;