From d4d0b417cbff40dfdf3d228509f43639bb34db9f Mon Sep 17 00:00:00 2001 From: Justin Seyster Date: Mon, 7 Feb 2011 21:48:26 -0500 Subject: [PATCH] Pass a tracecut index with each advice call. Fail with TC_BAD_CONTEXT when tracecut calls occur after compilation starts. --- src/tracecut.c | 80 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/src/tracecut.c b/src/tracecut.c index f3ccbf1..1c44509 100644 --- a/src/tracecut.c +++ b/src/tracecut.c @@ -74,6 +74,8 @@ struct tc_call_symbol { }; struct tc_tracecut { + int index; + struct tc_param *param_list; struct tc_call_symbol *symbol_list; @@ -98,6 +100,10 @@ struct tc_tracecut { 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) { @@ -141,6 +147,9 @@ tc_add_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; @@ -212,6 +221,9 @@ tc_add_call_symbol (struct tc_tracecut *tc, const char *name, { struct tc_call_symbol *symbol = NULL; + if (tc_in_compilation) + return TC_BAD_CONTEXT; + if (lookup_call_symbol (tc, name) != NULL) return TC_DUPLICATE;; @@ -291,6 +303,9 @@ enum tc_error 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; @@ -314,25 +329,34 @@ enum tc_error 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; @@ -377,19 +401,33 @@ tc_free_tracecut (struct tc_tracecut *tc) 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; @@ -409,6 +447,7 @@ capture_call_bindings (struct aop_joinpoint *jp, struct tc_call_symbol *symbol) { 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); @@ -424,11 +463,12 @@ capture_call_bindings (struct aop_joinpoint *jp, struct tc_call_symbol *symbol) /* 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 { @@ -440,24 +480,27 @@ static void 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); } } @@ -502,6 +545,15 @@ tracecut_pass (void) { 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); -- 2.34.1