# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
-FILE_PATTERNS = aop.h tracecut.h *.c
+FILE_PATTERNS = aop.h tracecut.h tracecut-advice.h *.c
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
libtracecut_la_SOURCES = tracecut-advice.c nfa.c nfa.h
libtracecut_la_CFLAGS = -Wall -Werror -fvisibility=hidden
-include_HEADERS = aop.h tracecut.h
+include_HEADERS = aop.h tracecut.h tracecut-advice.h
#include <string.h>
#include "nfa.h"
+#include "tracecut-advice.h"
/* Advice functions should be externally visible. */
#define ADVICE_FUNC __attribute__((visibility("default")))
static struct tracecut *tracecut_array = NULL;
-struct param_val {
- enum {
- PV_VACANT = 0,
- PV_POINTER,
- PV_SIGNED_INT,
- PV_UNSIGNED_INT,
- PV_FP
- } kind;
-
- union {
- uintptr_t ptr_value;
- int64_t int_val;
- uint64_t uint_val;
- double fp_val;
- };
-};
-
struct event {
int symbol_index;
}
}
-void
-tc_report_match (struct tracecut *tc, struct tuple *tuple, int symbol_index)
+__attribute__((weak)) __attribute__((noinline)) void
+tc_report_match (const char *symbol, const struct matched_param *param_array,
+ int num_params)
{
- fprintf (stderr, "(Tracecut) Match triggered by symbol: %s.", tc->symbol_names[symbol_index]);
+ fprintf (stderr, "(Tracecut) Match triggered by symbol: %s.", symbol);
- if (tc->num_params > 0)
+ if (num_params > 0)
{
int i;
fprintf (stderr, " Param values follow:\n");
- for (i = 0; i < tc->num_params; i++)
- fprintf (stderr, " Param %s: 0x%p\n", tc->param_names[i],
- (void *)tuple->param_vals[i].ptr_value);
+ for (i = 0; i < num_params; i++)
+ {
+ const char *name = param_array[i].name;
+ const struct param_val *value = param_array[i].value;
+
+ fprintf (stderr, " Param %s: ", name);
+
+ switch (value->kind)
+ {
+ case PV_POINTER:
+ fprintf (stderr, " %p\n", (void *)value->ptr_value);
+ break;
+ default:
+ fprintf (stderr, " Bad value\n");
+ }
+ }
}
else
{
}
}
+static void
+report_match (struct tracecut *tc, struct tuple *tuple, int symbol_index)
+{
+ int i;
+ struct matched_param *param_array;
+
+ param_array = alloca (tc->num_params * sizeof (struct matched_param));
+ for (i = 0; i < tc->num_params; i++)
+ {
+ param_array[i].name = tc->param_names[i];
+ param_array[i].value = &tuple->param_vals[i];
+ }
+
+ tc_report_match (tc->symbol_names[symbol_index], param_array, tc->num_params);
+}
+
static void
insert_tuple (struct tracecut *tc, struct tuple *tuple)
{
{
step (tuple->states[i], symbol_index);
if (ismatch (tuple->states[i]))
- tc_report_match (tc, tuple, symbol_index);
+ report_match (tc, tuple, symbol_index);
if (isatstart (tuple->states[i]))
num_trivial++;
break;
case PV_SIGNED_INT:
if (tuple->param_vals[i].kind != PV_SIGNED_INT
- || event->param_vals[i].int_val != tuple->param_vals[i].int_val)
+ || event->param_vals[i].int_value != tuple->param_vals[i].int_value)
return 0; /* Mismatch. */
else
; /* This param matches; keep looking. */
break;
case PV_UNSIGNED_INT:
if (tuple->param_vals[i].kind != PV_UNSIGNED_INT
- || event->param_vals[i].uint_val != tuple->param_vals[i].uint_val)
+ || event->param_vals[i].uint_value != tuple->param_vals[i].uint_value)
return 0; /* Mismatch. */
else
; /* This param matches; keep looking. */
break;
case PV_FP:
if (tuple->param_vals[i].kind != PV_FP
- || event->param_vals[i].fp_val != tuple->param_vals[i].fp_val)
+ || event->param_vals[i].fp_value != tuple->param_vals[i].fp_value)
return 0; /* Mismatch. */
else
; /* This param matches; keep looking. */
fatal_tracecut_error ("Out-of-bounds param value.");
}
- current_event->param_vals[param_index].kind = PV_SIGNED_INT;
- current_event->param_vals[param_index].int_val = param_val;
+ current_event->param_vals[param_index].kind = PV_SIGNED_INT;
+ current_event->param_vals[param_index].int_value = param_val;
}
ADVICE_FUNC void
fatal_tracecut_error ("Out-of-bounds param value.");
}
- current_event->param_vals[param_index].kind = PV_UNSIGNED_INT;
- current_event->param_vals[param_index].uint_val = param_val;
+ current_event->param_vals[param_index].kind = PV_UNSIGNED_INT;
+ current_event->param_vals[param_index].uint_value = param_val;
}
ADVICE_FUNC void
fatal_tracecut_error ("Out-of-bounds param value.");
}
- current_event->param_vals[param_index].kind = PV_FP;
- current_event->param_vals[param_index].fp_val = param_val;
+ current_event->param_vals[param_index].kind = PV_FP;
+ current_event->param_vals[param_index].fp_value = param_val;
}
--- /dev/null
+#ifndef __AOP_TRACECUT_ADVICE_H__
+#define __AOP_TRACECUT_ADVICE_H__
+
+/* Copyright (c) 2011 Justin Seyster
+ Copyright (c) 2011 Erez Zadok
+ Copyright (c) 2011 Stony Brook University
+ Copyright (c) 2011 The Research Foundation of SUNY
+
+ This program is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License
+ and a copy of the GCC Runtime Library Exception along with this
+ program; see the files COPYING and COPYING.RUNTIME respectively.
+ If not, see <http://www.gnu.org/licenses/>. */
+
+/**
+ * \file tracecut-advice.h
+ * \brief Public interface for implementing tracut advice functions.
+ *
+ * When the tracecut monitoring engine matches a tracecut rule, it
+ * calls the tracecut match function, tc_report_match(). By default,
+ * tc_report_match() just prints information about the match to
+ * <code>stderr</code>, but it is possible to override
+ * tc_report_match() to perform some other action.
+ *
+ * Note that this include file is not intended for tracecut
+ * <i>plug-ins</i>. Rather, it is intended for tracecut advice, which
+ * gets compiled and linked with the target program.
+ */
+
+/**
+ * \brief Value of a param.
+ *
+ * Stores the value of a param, along with what kind of param it is.
+ * There are four kinds of param, PV_POINTER, PV_SIGNED_INT,
+ * PV_UNSIGNED_INT, and PV_FP. PV_VACANT is used internally; no param
+ * with kind PV_VACANT will ever be passed to tc_report_match().
+ *
+ * The param's value itself is stored in a transparent union. You
+ * should only ever access the vaue using the union member that
+ * corresponds to the param's kind. You can access a transparent
+ * union member as if it were a member of the struct.
+ */
+struct param_val {
+ enum {
+ PV_VACANT = 0,
+ PV_POINTER,
+ PV_SIGNED_INT,
+ PV_UNSIGNED_INT,
+ PV_FP
+ } kind;
+
+ union {
+ uintptr_t ptr_value;
+ int64_t int_value;
+ uint64_t uint_value;
+ double fp_value;
+ };
+};
+
+/**
+ * \brief The name and value of a param.
+ */
+struct matched_param
+{
+ const char *name;
+ const struct param_val *value;
+};
+
+/**
+ * This function gets called at runtime when a tracecut rule matches.
+ * Because it is marked as a weak symbol, if the target program (or
+ * some other library) implements tc_report_match(), it will override
+ * the default implementation.
+ *
+ * The default implementation prints the symbol that triggered the
+ * match and the value of each param to <code>stderr</code>.
+ *
+ * \param symbol The name of the symbol that triggered the match.
+ * \param param_array A list of params associated with the tracecut.
+ * Each entry in the array has the param's name, as well as its value.
+ * \param num_params The number of elements in the param_array list.
+ */
+extern void tc_report_match (const char *symbol,
+ const struct matched_param *param_array,
+ int num_params);
+
+#endif