};
struct tc_tracecut {
+ int index;
+
struct tc_param *param_list;
struct tc_call_symbol *symbol_list;
main tracecut pass has access to them. */
static struct tc_tracecut *tracecut_list = NULL;
+/* This is true once actual compilation passes start, making it
+ illegal to modify any existing tracecut objects. */
+static int tc_in_compilation = 0;
+
static struct tc_param *
lookup_param (struct tc_tracecut *tc, const char *name)
{
{
struct tc_param *param = NULL;
+ if (tc_in_compilation)
+ return TC_BAD_CONTEXT;
+
if (!aop_is_pointer_type (type))
return TC_INVAL;
{
struct tc_call_symbol *symbol = NULL;
+ if (tc_in_compilation)
+ return TC_BAD_CONTEXT;
+
if (lookup_call_symbol (tc, name) != NULL)
return TC_DUPLICATE;;
tc_bind_to_call_param (struct tc_tracecut *tc, const char *param_name,
const char *symbol_name, int call_param_index)
{
+ if (tc_in_compilation)
+ return TC_BAD_CONTEXT;
+
if (call_param_index < 0)
return TC_INVAL;
tc_bind_to_return_value (struct tc_tracecut *tc, const char *param_name,
const char *symbol_name)
{
+ if (tc_in_compilation)
+ return TC_BAD_CONTEXT;
+
return add_call_symbol_binding (tc, param_name, symbol_name, -1);
}
/**
* Create an empty tc_tracecut object. The caller is responsible for
- * freeing the object using tc_free_tracecut().
+ * freeing the object using tc_free_tracecut(). (Do not use the
+ * standard free function.)
* \return A new tc_tracecut that must be freed with
- * tc_free_tracecut(). The return value can be NULL if allocation
- * fails.
+ * tc_free_tracecut(). The return value will be NULL if allocation
+ * fails or if compilation has already started..
*/
struct tc_tracecut *
tc_create_tracecut (void)
{
struct tc_tracecut *tc;
+ /* Illegal to create a tracecut once compilation has begun. */
+ if (tc_in_compilation)
+ return NULL;
+
tc = (struct tc_tracecut *)malloc (sizeof (struct tc_tracecut));
if (tc == NULL)
return NULL;
+ tc->index = -1;
tc->next_param_index = 0;
tc->next_symbol_index = 0;
tc->param_list = NULL;
free(tc);
}
+/* Go through the master list of tracecuts and give each a consecutive
+ index. */
+static void
+assign_tracecut_indices ()
+{
+ int next_tracecut_index = 0;
+ struct tc_tracecut *tc;
+
+ for (tc = tracecut_list; tc != NULL; tc = tc->next)
+ tc->index = next_tracecut_index++;
+}
+
/* 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,
+insert_begin_event_advice (struct aop_joinpoint *jp, int tc_index,
struct tc_call_symbol *symbol)
{
- aop_insert_advice (jp, "_tc_event_begin", symbol->location, AOP_TERM_ARG);
+ aop_insert_advice (jp, "_tc_event_begin", symbol->location,
+ AOP_INT_CST (tc_index), 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)
+capture_call_bindings (struct aop_joinpoint *jp, int tc_index,
+ struct tc_call_symbol *symbol)
{
struct tc_call_binding *binding;
{
aop_cast_to_all_pointer (param_val);
aop_insert_advice (jp, "_tc_capture_pointer_param", symbol->location,
+ AOP_INT_CST (tc_index),
AOP_INT_CST (symbol->index),
AOP_INT_CST (binding->param->index),
AOP_DYNVAL (param_val), AOP_TERM_ARG);
/* 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,
+insert_transition_event_advice (struct aop_joinpoint *jp, int tc_index,
struct tc_call_symbol *symbol)
{
aop_insert_advice (jp, "_tc_event_transition", symbol->location,
- AOP_INT_CST (symbol->index), AOP_TERM_ARG);
+ AOP_INT_CST (tc_index), AOP_INT_CST (symbol->index),
+ AOP_TERM_ARG);
}
struct join_on_call_arg {
join_on_call (struct aop_joinpoint *jp, void *callback_arg)
{
struct join_on_call_arg *arg = callback_arg;
+ struct tc_tracecut *tc = arg->tc;
struct tc_call_symbol *symbol = arg->symbol;
+ int tc_index = tc->index;
+
/* 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);
+ insert_begin_event_advice (jp, tc_index, symbol);
+ capture_call_bindings (jp, tc_index, symbol);
+ insert_transition_event_advice (jp, tc_index, 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);
+ insert_transition_event_advice (jp, tc_index, symbol);
+ capture_call_bindings (jp, tc_index, symbol);
+ insert_begin_event_advice (jp, tc_index, symbol);
}
}
{
struct tc_tracecut *tc;
+ if (!tc_in_compilation)
+ {
+ /* Choose an index for every tracecut object. After that,
+ tracecut objects are frozen because setting tc_in_compilation
+ to true makes it illegal to modify them. */
+ assign_tracecut_indices ();
+ tc_in_compilation = 1;
+ }
+
for (tc = tracecut_list; tc != NULL; tc = tc->next)
add_instrumentation_for_tracecut (tc);