Add tracecut pass that can instrument events reference in tracecuts.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Fri, 4 Feb 2011 21:17:11 +0000 (16:17 -0500)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Fri, 4 Feb 2011 21:17:11 +0000 (16:17 -0500)
Add error return codes.

src/tracecut.c
src/tracecut.h

index f7cb7d1f8146af7d21cee4c97a64ae0f88c8f7a6..51c73d0b76ef342cf48c7d39a45cdd2b1b7712c8 100644 (file)
  */
 struct tc_call_symbol {
   const char *name;
+  int index;
+
   const char *func_name;
+  enum aop_insert_location location;
 
   struct tc_call_symbol *next;
 };
@@ -52,6 +55,9 @@ struct tc_call_symbol {
 struct tc_tracecut {
   struct tc_call_symbol *symbol_list;
 
+  /* Each symbol gets a unique index. */
+  int next_symbol_index;
+
   struct tc_tracecut *next;
 };
 /**
@@ -98,35 +104,49 @@ symbol_exists (struct tc_tracecut *tc, const char *name)
  * \param location Specifies whether the the symbol event should
  * trigger before or after the specified function is called.
  */
-void
+enum tc_error
 tc_add_call_symbol (struct tc_tracecut *tc, const char *name,
                    const char *func_name, enum aop_insert_location location)
 {
-  struct tc_call_symbol *symbol;
+  struct tc_call_symbol *symbol = NULL;
 
   if (symbol_exists (tc, name))
-    {
-      fprintf (stderr, "(Tracecut) Ignoring duplicate symbol: %s\n", name);
-      return;
-    }
+    return TC_DUPLICATE;;
 
   symbol = (struct tc_call_symbol *)malloc (sizeof (struct tc_call_symbol));
-  aop_assert (symbol != NULL);
+  if (symbol == NULL)
+    goto nomem;
 
   symbol->name = strdup (name);
   symbol->func_name = strdup (func_name);
-  aop_assert (symbol->name != NULL && symbol->func_name != NULL);
+  if (symbol->name == NULL || symbol->func_name == NULL)
+    goto nomem;
+
+  symbol->index = tc->next_symbol_index++;
+  symbol->location = location;
 
   /* Insert this new symbol into the list of call symbols. */
   symbol->next = tc->symbol_list;
   tc->symbol_list = symbol;
+
+  return TC_SUCCESS;
+
+ nomem:
+  if (symbol != NULL)
+    {
+      free ((char *)symbol->name);
+      free ((char *)symbol->func_name);
+      free (symbol);
+    }
+  return TC_NOMEM;
 }
 
 /**
  * Create an empty tc_tracecut object.  The caller is responsible for
  * freeing the object using tc_free_tracecut().
  * \return A new tc_tracecut that must be freed with
- * tc_free_tracecut().
+ * tc_free_tracecut().  The return value can be NULL if allocation
+ * fails.
  */
 struct tc_tracecut *
 tc_create_tracecut (void)
@@ -134,10 +154,16 @@ tc_create_tracecut (void)
   struct tc_tracecut *tc;
 
   tc = (struct tc_tracecut *)malloc (sizeof (struct tc_tracecut));
-  aop_assert (tc != NULL);
+  if (tc == NULL)
+    return NULL;
 
+  tc->next_symbol_index = 0;
   tc->symbol_list = NULL;
 
+  /* Insert this tracecut into the master list. */
+  tc->next = tracecut_list;
+  tracecut_list = tc;
+
   return tc;
 }
 
@@ -160,7 +186,7 @@ remove_tracecut_from_list (struct tc_tracecut *tc)
 }
 
 /**
- * Free all the memory used by a tc_object.  Every call to
+ * Free all the memory used by a tc_tracecut object.  Every call to
  * tc_create_tracecut() should have a matching call to
  * tc_free_tracecut().
  * \param tc The tracecut object to free.
@@ -173,6 +199,57 @@ tc_free_tracecut (struct tc_tracecut *tc)
   free(tc);
 }
 
+struct join_on_call_param {
+  struct tc_tracecut *tc;
+  struct tc_call_symbol *symbol;
+};
+
+static void
+join_on_call (struct aop_joinpoint *jp, void *callback_param)
+{
+  struct join_on_call_param *param = callback_param;
+  struct tc_call_symbol *symbol = param->symbol;
+
+  aop_insert_advice (jp, "_tc_event_transition", symbol->location,
+                    AOP_INT_CST (symbol->index), AOP_TERM_ARG);
+}
+
+static void
+add_instrumentation_for_tracecut (struct tc_tracecut *tc)
+{
+  struct tc_call_symbol *symbol;
+
+  for (symbol = tc->symbol_list; symbol != NULL; symbol = symbol->next)
+    {
+      struct join_on_call_param param;
+      struct aop_pointcut *pc;
+
+      pc = aop_match_function_call ();
+      aop_filter_call_pc_by_name (pc, symbol->func_name);
+
+      param.tc = tc;
+      param.symbol = symbol;
+      aop_join_on (pc, join_on_call, &param);
+    }
+}
+
+static unsigned int
+tracecut_pass (void)
+{
+  struct tc_tracecut *tc;
+
+  for (tc = tracecut_list; tc != NULL; tc = tc->next)
+    add_instrumentation_for_tracecut (tc);
+
+  return 0;
+}
+
+void
+tc_register_tracecut_pass (void)
+{
+  aop_register_pass ("tracecut", tracecut_pass);
+}
+
 /* Close Doxygen defgroup block. */
 /**
  * \}
index c492e3965f4b050f9b16dcb53b009b8977727b14..02996575c592e2b74c5c92f0f97493d2bd2d5820 100644 (file)
 
 struct tc_tracecut;
 
-extern void tc_add_call_symbol (struct tc_tracecut *tc, const char *name,
-                               const char *func_name,
-                               enum aop_insert_location location);
+/**
+ * Possible error return values for tracecut functions.
+ */
+enum tc_error {
+  /**
+   * No error: the function succeeded.
+   */
+  TC_SUCCESS,
+
+  /**
+   * Function was called from an inappropriate context.  Most tracecut
+   * functions should be called from your aop_main() function.
+   */
+  TC_BAD_CONTEXT,
+
+  /**
+   * Attempt to create a duplicate name.
+   */
+  TC_DUPLICATE,
+
+  /**
+   * Attempt to reference a name that does not exist.
+   */
+  TC_NOENT,
+
+  /**
+   * Function could not allocate enough memory.
+   */
+  TC_NOMEM,
+};
+
+extern enum tc_error tc_add_call_symbol (struct tc_tracecut *tc,
+                                        const char *name,
+                                        const char *func_name,
+                                        enum aop_insert_location location);
 
 extern struct tc_tracecut *tc_create_tracecut (void);
 extern void tc_free_tracecut (struct tc_tracecut *tc);
 
+extern void tc_register_tracecut_pass (void);
+
 #endif