From 589c13d75771e9aebed8114f099cd7d291078a32 Mon Sep 17 00:00:00 2001 From: Justin Seyster Date: Mon, 7 Mar 2011 21:33:03 -0500 Subject: [PATCH] Added some more convenient error handling. --- src/tracecut.c | 89 +++++++++++++++++++++++++++++++++--------- src/tracecut.h | 3 ++ test/plugin-tracecut.c | 6 +++ 3 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/tracecut.c b/src/tracecut.c index 17883c1..d44d817 100644 --- a/src/tracecut.c +++ b/src/tracecut.c @@ -91,6 +91,10 @@ struct tc_tracecut { /* Each symbol gets a unique index. */ int next_symbol_index; + /* The first tracecut operation that fails stores its error code + here. */ + enum tc_error tc_error; + struct tc_tracecut *next; }; /** @@ -151,6 +155,52 @@ lookup_param (struct tc_tracecut *tc, const char *name) return NULL; } +/* Here's a cool trick I learned from the DTrace source code. This + function sets the error code in a tracecut object and also returns + that error code, so you can conveniently nestle it in the return + statement itself. */ +static enum tc_error +return_error (struct tc_tracecut *tc, enum tc_error tc_error) +{ + /* The tc_error field holds the _first_ non success error code. */ + if (tc->tc_error == TC_SUCCESS) + tc->tc_error = tc_error; + + return tc_error; +} + +/** + * The first operation on a tracecut that fails stores its error code + * in the tracecut. This function returns that error code, or + * #TC_SUCCESS if all operations succeeded. Checking error codes this + * ways makes it possible to call several tracecut functions in + * sequence without individually checking their error codes. + * + * Use tc_reset_error() to set a tracecut's error code back to + * #TC_SUCCESS. + * + * \param tc The tracecut to check. + * \return The error code of the first failed operation on this + * tracecut, or TC_SUCCESS if no operations failed. + */ +enum tc_error +tc_error_code (struct tc_tracecut *tc) +{ + return tc->tc_error; +} + +/** + * Clear the history of any failed operations on this tracecut. After + * calling this, tc_error_code() will return #TC_SUCCESS until some + * later tracecut operation fails. + * \param tc The tracecut to reset. + */ +void +tc_reset_error (struct tc_tracecut *tc) +{ + tc->tc_error = TC_SUCCESS; +} + /** * Add a new tracecut parameter. Each tracecut tracks several * objects, so a tracecut event must be parameterized to @@ -180,13 +230,13 @@ tc_add_param (struct tc_tracecut *tc, const char *name, struct tc_param *param = NULL; if (tc_in_compilation) - return TC_BAD_CONTEXT; + return return_error (tc, TC_BAD_CONTEXT); if (!aop_is_pointer_type (type)) - return TC_INVAL; + return return_error (tc, TC_INVAL); if (lookup_param (tc, name) != NULL) - return TC_DUPLICATE;; + return return_error (tc, TC_DUPLICATE); param = (struct tc_param *)malloc (sizeof (struct tc_param)); if (param == NULL) @@ -203,11 +253,11 @@ tc_add_param (struct tc_tracecut *tc, const char *name, param->next = tc->param_list; tc->param_list = param; - return TC_SUCCESS; + return return_error (tc, TC_SUCCESS); nomem: free (param); - return TC_NOMEM; + return return_error (tc, TC_NOMEM); } static struct tc_call_symbol * @@ -254,10 +304,10 @@ 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; + return return_error (tc, TC_BAD_CONTEXT); if (lookup_call_symbol (tc, name) != NULL) - return TC_DUPLICATE;; + return return_error (tc, TC_DUPLICATE); symbol = (struct tc_call_symbol *)malloc (sizeof (struct tc_call_symbol)); if (symbol == NULL) @@ -276,7 +326,7 @@ tc_add_call_symbol (struct tc_tracecut *tc, const char *name, symbol->next = tc->symbol_list; tc->symbol_list = symbol; - return TC_SUCCESS; + return return_error (tc, TC_SUCCESS); nomem: if (symbol != NULL) @@ -285,7 +335,7 @@ tc_add_call_symbol (struct tc_tracecut *tc, const char *name, free ((char *)symbol->func_name); free (symbol); } - return TC_NOMEM; + return return_error (tc, TC_NOMEM); } static enum tc_error @@ -299,11 +349,11 @@ add_call_symbol_binding (struct tc_tracecut *tc, const char *param_name, param = lookup_param (tc, param_name); symbol = lookup_call_symbol (tc, symbol_name); if (param == NULL || symbol == NULL) - return TC_NOENT; + return return_error (tc, TC_NOENT); binding = (struct tc_call_binding *)malloc (sizeof (struct tc_call_binding)); if (binding == NULL) - return TC_NOMEM; + return return_error (tc, TC_NOMEM); binding->call_param_index = index; binding->param = param; @@ -312,7 +362,7 @@ add_call_symbol_binding (struct tc_tracecut *tc, const char *param_name, binding->next = symbol->binding_list; symbol->binding_list = binding; - return TC_SUCCESS; + return return_error (tc, TC_SUCCESS); } /** @@ -336,10 +386,10 @@ 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; + return return_error (tc, TC_BAD_CONTEXT); if (call_param_index < 0) - return TC_INVAL; + return return_error (tc, TC_INVAL); return add_call_symbol_binding (tc, param_name, symbol_name, call_param_index); @@ -362,7 +412,7 @@ 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 return_error (tc, TC_BAD_CONTEXT); return add_call_symbol_binding (tc, param_name, symbol_name, -1); } @@ -385,25 +435,25 @@ tc_add_rule (struct tc_tracecut *tc, const char *specification) struct tc_rule *rule; if (tc_in_compilation) - return TC_BAD_CONTEXT; + return return_error (tc, TC_BAD_CONTEXT); rule = (struct tc_rule *)malloc (sizeof (struct tc_rule)); if (rule == NULL) - return TC_NOMEM; + return return_error (tc, TC_NOMEM); /* TODO: Check syntax*/ rule->specification = strdup (specification); if (rule->specification == NULL) { free (rule); - return TC_NOMEM; + return return_error (tc, TC_NOMEM); } /* Add this to the tracecut's list of rules. */ rule->next = tc->rule_list; tc->rule_list = rule; - return TC_SUCCESS; + return return_error (tc, TC_SUCCESS); } /** @@ -432,6 +482,7 @@ tc_create_tracecut (void) tc->next_symbol_index = 0; tc->param_list = NULL; tc->symbol_list = NULL; + tc->tc_error = TC_SUCCESS; tc->rule_list = NULL; /* Insert this tracecut into the master list. */ diff --git a/src/tracecut.h b/src/tracecut.h index 7bcfb3f..64f017d 100644 --- a/src/tracecut.h +++ b/src/tracecut.h @@ -80,6 +80,9 @@ enum tc_error { TC_NOMEM, }; +extern enum tc_error tc_error_code (struct tc_tracecut *tc); +extern void tc_reset_error (struct tc_tracecut *tc); + extern enum tc_error tc_add_param (struct tc_tracecut *tc, const char *name, const struct aop_type *type); diff --git a/test/plugin-tracecut.c b/test/plugin-tracecut.c index f6681d0..cb2f49c 100644 --- a/test/plugin-tracecut.c +++ b/test/plugin-tracecut.c @@ -42,6 +42,8 @@ AOP_MAIN_PROTO aop_main() tc_add_rule(tc_foo, "get inc* dec"); + aop_assert(tc_error_code(tc_foo) == TC_SUCCESS); + /* Tracecut for bar objects. */ tc_bar = tc_create_tracecut(); @@ -58,6 +60,8 @@ AOP_MAIN_PROTO aop_main() tc_add_rule(tc_bar, "get double* half"); + aop_assert(tc_error_code(tc_bar) == TC_SUCCESS); + /* Tracecut for both objects. */ tc_both = tc_create_tracecut(); @@ -70,6 +74,8 @@ AOP_MAIN_PROTO aop_main() tc_add_rule(tc_both, "transfer transfer"); + aop_assert(tc_error_code(tc_both) == TC_SUCCESS); + aop_register_pass("init_tracecut", init_pass); tc_register_tracecut_pass(); } -- 2.34.1