lib_LTLIBRARIES = libinteraspect.la
libinteraspect_la_SOURCES = aop-pc-assign.c aop-main.c aop-type.c aop-weave.c \
- aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c aop-header.c
- aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c aop-pointcut.c \
- aop-duplicate.c
++ aop-pc-entry.c aop-pc-exit.c aop-pc-fun-call.c aop-header.c \
++ aop-pointcut.c aop-duplicate.c
libinteraspect_la_CFLAGS = -Wall -Werror -fvisibility=hidden -prefer-pic
libinteraspect_la_LDFLAGS = -static -prefer-pic -version-info 1:0:0
libinteraspect_la_CPPFLAGS = -DHAVE_CONFIG_H -DIN_GCC -I$(gcc_includes)
#include <c-common.h>
#include "aop.h"
+ #include "aop-duplicate.h"
+#include "aop-header.h"
#include "aop-pointcut.h"
+ #include "aop-type.h"
//#define PAUSE_ON_START
static void
aop_cleanup (void *event_date, void *data)
{
+ free_type_table ();
+ free_prototype_table ();
cleanup_passes ();
}
aop_plugin_name = plugin_info->base_name;
- /* Initialization for aop-type.c. */
++ /* Initialization for aop-type.c and aop-header.c. */
+ init_type_table ();
+ init_prototype_table ();
/* Register our cleanup function. */
register_callback (aop_plugin_name, PLUGIN_FINISH, aop_cleanup, NULL);
bool
does_type_match (tree gcc_type, const struct aop_type *aop_type)
{
+ int pointer_levels;
+
aop_assert (gcc_type != NULL && aop_type != NULL);
- if (aop_type->kind == ATK_ALL_POINTER)
+ pointer_levels = aop_type->pointer_levels;
+ while (pointer_levels > 0)
{
- return (TREE_CODE (gcc_type) == POINTER_TYPE);
+ if (TREE_CODE (gcc_type) != POINTER_TYPE)
+ return false;
+
+ /* What type does it point to? */
+ gcc_type = TREE_TYPE (gcc_type);
+ pointer_levels--;
}
- else if (aop_type->pointer_levels == 0)
+
+ switch (aop_type->kind)
{
- switch (aop_type->kind)
- {
- case ATK_ALL_SIGNED:
- return (TREE_CODE (gcc_type) == INTEGER_TYPE
- && !TYPE_UNSIGNED (gcc_type));
- case ATK_ALL_UNSIGNED:
- return (TREE_CODE (gcc_type) == INTEGER_TYPE
- && TYPE_UNSIGNED (gcc_type));
- case ATK_ALL_FP:
- return (TREE_CODE (gcc_type) == REAL_TYPE);
- default:
- break;
- }
+ case ATK_ALL_POINTER:
+ return (TREE_CODE (gcc_type) == POINTER_TYPE);
+ case ATK_SIGNED_INT:
+ case ATK_UNSIGNED_INT:
+ return does_int_type_match (gcc_type, aop_type->kind, aop_type->size);
+ case ATK_FP:
+ return does_fp_type_match (gcc_type, aop_type->size);
+ case ATK_STRUCT:
+ case ATK_UNION:
+ case ATK_ENUM:
+ return does_custom_type_match (gcc_type, aop_type->kind, aop_type->tag);
+ default:
+ aop_assert (0);
}
-
- aop_assert (0);
}
- goto terminate;
+
+/* Return true if two aop_type objects are equal. */
+bool
+are_types_equal (const struct aop_type *a, const struct aop_type *b)
+{
+ return (a == b);
+}
+
+/* C names for special aop_type objects. */
+static const char *all_signed_name = "ALL_SIGNED_T";
+static const char *all_unsigned_name = "ALL_UNSIGNED_T";
+static const char *all_fp_name = "ALL_FP_T";
+static const char *all_pointer_name = "ALL_POINTER_T";
+
+/* Format an aop_type as a C/C++ typename. The result is stored in
+ the output buffer (n is the size of the buffer). Returns the
+ number characters written (but without regard to truncation because
+ of a too small output buffer, as with snprintf()). */
+int
+format_c_type (const struct aop_type *type, int n, char *output)
+{
+ int size;
+
+ if (type->kind == ATK_ALL_POINTER)
+ {
+ size = snprintf (output, n, "%s", all_pointer_name);
- else if (type->pointer_levels == 0)
+ }
- switch (type->kind)
- {
- case ATK_ALL_SIGNED:
- size = snprintf (output, n, "%s", all_signed_name);
- goto terminate;
- case ATK_ALL_UNSIGNED:
- size = snprintf (output, n, "%s", all_unsigned_name);
- goto terminate;
- case ATK_ALL_FP:
- size = snprintf (output, n, "%s", all_fp_name);
- goto terminate;
- default:
- break;
- }
++ else if (is_all_integer_type (type))
+ {
- aop_assert (0);
-
- terminate:
++ if (type->kind == ATK_SIGNED_INT)
++ size = snprintf (output, n, "%s", all_signed_name);
++ else if (type->kind == ATK_UNSIGNED_INT)
++ size = snprintf (output, n, "%s", all_unsigned_name);
++ else
++ aop_assert (0); /* Should never happen. */
++ }
++ else if (is_all_fp_type (type))
++ {
++ size = snprintf (output, n, "%s", all_fp_name);
++ }
++ else
++ {
++ aop_assert (0); /* Not yet supported. */
+ }
+
+ /* Before returning, make absolutely sure that the result is
+ NULL-terminated. Note that snprintf will not terminate a string
+ that it has to truncate because of too small buffer. */
+ if (size < n)
+ output[size] = '\0';
+ else
+ output[n - 1] = '\0';
+
+ return size;
+}
int pointer_levels;
const char *tag;
+
+ int size;
};
- bool does_type_match (tree gcc_type, const struct aop_type *aop_type);
- bool are_types_equal (const struct aop_type *a, const struct aop_type *b);
+ extern void init_type_table ();
+ extern void free_type_table ();
+
+ extern bool is_all_integer_type (const struct aop_type *type);
+ extern bool is_all_fp_type (const struct aop_type *type);
+ extern bool does_type_match (tree gcc_type, const struct aop_type *aop_type);
- int format_c_type (const struct aop_type *type, int n, char *output);
++extern bool are_types_equal (const struct aop_type *a,
++ const struct aop_type *b);
++extern int format_c_type (const struct aop_type *type, int n, char *output);
+
#endif
#undef GENERATOR_FILE
#include "aop.h"
+ #include "aop-duplicate.h"
#include "aop-dynval.h"
+#include "aop-header.h"
#include "aop-pointcut.h"
+ #include "aop-type.h"
/* Throw a fatal error if a dynval is not allowed in a before-advice
call. */
pc->insert_before(jp, func_call);
else if(location == AOP_INSERT_AFTER)
pc->insert_after(jp, func_call);
-
}
+
+ /**
+ * Duplicate the current function's body so that there are two copies
+ * available for instrumentation. A function entry join point is
+ * required because the duplication process inserts an advice call at
+ * function entry which serves as a <i>distributor</i>.
+ *
+ * The distributor advice decides which copy to execute. A
+ * distributor advice function returns an int (unlike regular advice,
+ * which has void return type): a zero value will execute the original
+ * copy and a non-zero value will execute the new copy.
+ *
+ * Any arguments following func_name are arguments to be passed to the
+ * distributor advice function. (See the documentation for
+ * aop_insert_advice() for an explanation of passing arguments to
+ * advice.) #AOP_TERM_ARG must be the last argument to
+ * aop_duplicate(), even when not specifying any arguments for the
+ * advice function.
+ *
+ * \param jp The function entry join point for the current join point.
+ * The distributor advice will be inserted here. Function entry join
+ * points are obtained by joining on an aop_match_function_entry()
+ * pointcut.
+ * \param func_name The name of the distributor advice function.
+ * \param ... A list of arguments to pass to the advice function,
+ * terminated by #AOP_TERM_ARG.
+ */
+ void
+ aop_duplicate (struct aop_joinpoint *jp, const char *func_name, ...)
+ {
+ va_list argp;
+ gimple func_call;
+ struct aop_pointcut *pc;
+
+ pc = jp->pc;
+
+ if (pc->kind != ATP_ENTRY)
+ fatal_error ("(InterAspect) Function duplication must be done on a"
+ " function entry join point.");
+ else if (jp->is_prepared)
+ fatal_error ("(InterAspect) Illegal to duplicate using a join point that"
+ " has already been used to insert advice.");
+ else if (is_current_func_duplicated())
+ fatal_error ("(InterAspect) Cannot duplicate a function more than once.");
+
+ va_start (argp, func_name);
+ func_call = build_gcc_call (func_name, integer_type_node, AOP_INSERT_BEFORE,
+ argp);
+ va_end (argp);
+
+ duplicate_function_body ("ia_body_index", func_call);
+ }
extern const char *aop_capture_lhs_name (struct aop_joinpoint *jp);
extern struct aop_dynval *aop_capture_assigned_value (struct aop_joinpoint *jp);
+extern int aop_write_c_header (const char *filename, const char *guard,
+ const char *license, const char *preamble);
+
++
+ /**
+ * \defgroup scope_val aop_capture_lhs_var_scope() Return Values
+ *
+ * The aop_capture_lhs_var_scope() returns one of these values when
+ * the variable assigned to does not have function local scope (or
+ * when the assignment does not assign directly to a variable).
+ * \{
+ */
+ /**
+ * The variable is accessible by name from anywhere in the program.
+ */
+ #define AOP_GLOBAL_SCOPE -1
+
+ /**
+ * The variable is only accessible by name from the current file.
+ */
+ #define AOP_FILE_SCOPE -2
+
+ /**
+ * Used for an assignment that does not assign to a variable. For
+ * example, the assignment may be to a field in a struct or a
+ * dereferenced pointer.
+ */
+ #define AOP_MEMORY_SCOPE -3
+
+ /**
+ * Use this macro to check if a variable has function-local scope.
+ */
+ #define AOP_LOCAL_SCOPE(SCOPE) (SCOPE >= 0)
+
+ /* Close Doxygen defgroup block. */
+ /**
+ * \}
+ */
+
+ extern int aop_capture_lhs_var_scope (struct aop_joinpoint *jp);
+
+ extern int aop_capture_lineno (struct aop_joinpoint *jp);
+
+ extern const char *aop_capture_file_name (struct aop_joinpoint *jp);
++
#endif