/* 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;
};
/**
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 <i>parameterized</i> to
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)
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 *
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)
symbol->next = tc->symbol_list;
tc->symbol_list = symbol;
- return TC_SUCCESS;
+ return return_error (tc, TC_SUCCESS);
nomem:
if (symbol != NULL)
free ((char *)symbol->func_name);
free (symbol);
}
- return TC_NOMEM;
+ return return_error (tc, TC_NOMEM);
}
static enum tc_error
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;
binding->next = symbol->binding_list;
symbol->binding_list = binding;
- return TC_SUCCESS;
+ return return_error (tc, TC_SUCCESS);
}
/**
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);
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);
}
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);
}
/**
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. */