1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
# Writing a plugin module for eztrace
## Introduction
This is an example of plugin module for eztrace.
This directory contains 2 sub-directories:
- `libexample_orig`
This is an example library with functions that we want to trace using
eztrace. This library implements two simple functions
(`example_function1` and `example_function2`).
This directory also includes a simple program that uses this library.
- `libexample_eztrace`
This directory contains an example plugin for eztrace. This plugin
allows to trace the libexample functions with eztrace.
## Creating an eztrace plugin
(see libexample_eztrace/example.c)
### Declaring a plugin
First let's give name to our plugin and declare it. This is done with a few C macros:
```
#define CURRENT_MODULE example
DECLARE_CURRENT_MODULE;
```
Then, we register the plugin to eztrace. This allows eztrace_avail to
describe available plugins, and to initialize all the plugins selected
by a user:
```
void __example_init(void) __attribute__ ((constructor));
/* Initialize the current library */
void __example_init(void) {
EZT_REGISTER_MODULE(example, "Example module", init_example, finalize_example);
}
```
### Instrumenting functions
For recording events, eztrace relies on functions that redefines the
functions that have to be traced (eg. MPI_Send, pthread_create, etc.)
Writing a plugin module for eztrace thus boils down to redefining all
the needed functions (for example `example_function1` and
`example_function2`). Each redefined function `f` has to record an event
and to call the original `f` function. Usually such a function looks
like this:
```
int f(int arg1, double arg2)
{
FUNCTION_ENTRY_WITH_ARGS(arg1, arg2);
int ret = f_orig(arg1, arg2);
FUNCTION_EXIT_WITH_ARGS(ret);
return ret;
}
```
This function records an event, calls the original `f` function, and
records another after `f`. In order to call the original `f`
function, we need to retrieve its address. This is done by describing the functions to be intercepted by eztrace:
```
PPTRACE_START_INTERCEPT_FUNCTIONS(example)
INTERCEPT3("f", f_orig)
INTERCEPT3("bar", bar_orig)
PPTRACE_END_INTERCEPT_FUNCTIONS(example);
```
This macro replace the original `f` function with the one defined in the
current module. It copies the address of the original function in the
`f_orig` variable.
We also need to provide an initialization function:
```
static void init_example() {
INSTRUMENT_FUNCTIONS(example);
if (eztrace_autostart_enabled())
eztrace_start();
__example_initialized = 1;
}
```
|