*/
struct tc_call_symbol {
const char *name;
+ int index;
+
const char *func_name;
+ enum aop_insert_location location;
struct tc_call_symbol *next;
};
struct tc_tracecut {
struct tc_call_symbol *symbol_list;
+ /* Each symbol gets a unique index. */
+ int next_symbol_index;
+
struct tc_tracecut *next;
};
/**
* \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)
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;
}
}
/**
- * 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.
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, ¶m);
+ }
+}
+
+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. */
/**
* \}
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