This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

here's an example tap file for RHEL 4 update 2


i've recently been introduced to systemtap. and along the way, i found
the example files found on this list to be quite helpful. so, i
figured i'd post my tap file in the hopes that:

1) someone else will find it useful, and
2) someone will explain to me how i could have done things much more simple.

in the tap file, you'll see some code sections that i needed to work
around some issues with the version of systemtap that is shipped with
RHEL 4 update 2 (version 0.4) -- for example, i had to write some code
to get the return value and some more code for i386 to get the return
value if the function returns a 64-bit value.

this tap file also interacts with the proc file system in order to
dynamically change what is monitored (rather than reloading the tap
file).

the purpose of the tap file is record all open, read, write, seek,
socket and close system calls for each program that are separated by a
comma in the global variable 'traced_apps'.

any and all comments are appreciated -- here's the code:

=======================================
/*
 * this code is used to put a file into the proc file system that is used
 * by this systemtap program to determine which programs to trace.
 *
 * the file is: /proc/sys/debug/traced-apps
 *
 * for example, to trace 'iozone', after starting this systemtap file,
 * on the command line execute:
 *
 *      echo "iozone" > /proc/sys/debug/traced-apps
 */

%{
#include <linux/sysctl.h>

/*
 * a 'handle' used to deallocate the proc fs table
 */
struct ctl_table_header *app_trace_proc_fs;

#define MAX_TRACED_APPS_SIZE    1024


char traced_apps[MAX_TRACED_APPS_SIZE] = "";
char working_traced_apps[MAX_TRACED_APPS_SIZE];

static ctl_table app_trace_table[] = {
        {
                .ctl_name       = 1,
                .procname       = "traced-apps",
                .data           = &traced_apps,
                .maxlen         = MAX_TRACED_APPS_SIZE,
                .mode           = 0644,
                .proc_handler   = &proc_dostring,
                .strategy       = &sysctl_string,
        },

        { .ctl_name = 0 }
};

static ctl_table app_trace_root_table[] = {
        {
                .ctl_name = CTL_DEBUG,
                .procname = "debug",
                .mode = 0555,
                .child = app_trace_table,
        },

        { .ctl_name = 0 }
};
%}


function get_returnvalue:long () %{
        if (CONTEXT->regs) {
#if defined (__x86_64__)
                THIS->__retvalue = CONTEXT->regs->rax;
#elif defined (__i386__)
                THIS->__retvalue = (unsigned long)CONTEXT->regs->eax;
#endif
        } else {
                THIS->__retvalue = 0;
        }
%}

/*
 * seeks return 'long long' in x86. this is a way to get the hi 32 bits
 */
function get_hi_returnvalue:long () %{
        if (CONTEXT->regs) {
#if defined (__x86_64__)
                THIS->__retvalue = 0;
#elif defined (__i386__)
                THIS->__retvalue = (unsigned long)CONTEXT->regs->edx;
#endif
        } else {
                THIS->__retvalue = 0;
        }
%}


/*
 * get_fd() is called from llseek which is only called from i386 programs.
 * but, there is an __x86_64__ clause to make sure the program compiles
 * correctly.
 */
function get_fd:long (fd) %{
        if (CONTEXT->regs) {
#if defined (__x86_64__)
                THIS->__retvalue = THIS->fd;
#elif defined (__i386__)
                THIS->__retvalue = CONTEXT->regs->ebx;
#endif
        } else {
                THIS->__retvalue = 0;
        }
%}

function is_traced_call:long (name:string) %{
        char    *a;
        char    *b;

        strcpy(working_traced_apps, traced_apps);
        b = working_traced_apps;

        while ((a = strsep(&b, ","))) {
                if (!strcmp(a, THIS->name)) {
                        THIS->__retvalue = 1;
                        return;
                }
        }

        THIS->__retvalue = 0;
%}

function output_header(op, name, pid) {
        print(string(gettimeofday_us()) . " op: " . op);
        print(" execname: " . name);
        print(" pid: " . pid);
}

probe kernel.function("sys_open").return
{
        if (is_traced_call(execname())) {
                output_header("open", execname(), string(pid()));

                fd = get_returnvalue();
                print(" fd: " . string(fd) . "\n");
        }
}

probe kernel.function("sys_socket").return
{
        if (is_traced_call(execname())) {
                output_header("socket", execname(), string(pid()));

                fd = get_returnvalue();
                print(" fd: " . string(fd) . "\n");
        }
}

probe kernel.function("sys_read")
{
        if (is_traced_call(execname())) {
                output_header("read", execname(), string(pid()));

                fd = get_fd($fd);
                print(" fd: " . string(fd));
                print(" count: " . string($count) .  "\n");
        }
}

probe kernel.function("sys_write")
{
        if (is_traced_call(execname())) {
                output_header("write", execname(), string(pid()));

                fd = get_fd($fd);
                print(" fd: " . string(fd));
                print(" count: " . string($count) . "\n");
        }
}

probe kernel.function("sys_lseek")
{
        if (is_traced_call(execname())) {
                output_header("lseek", execname(), string(pid()));

                fd = get_fd($fd);
                print(" fd: " . string(fd));
        }
}

/*
 * llseek is only called on i386
 */
probe kernel.function("sys_llseek")
{
        if (is_traced_call(execname())) {
                output_header("llseek", execname(), string(pid()));

                fd = get_fd($fd);
                print(" fd: " . string(fd));
        }
}

probe kernel.function("vfs_llseek").return
{
        if (is_traced_call(execname())) {
                offset = get_returnvalue();
                hioffset = get_hi_returnvalue();

                if (hioffset > 0) {
                        offset = offset + (hioffset << 32);
                }

                print(" offset: " . string(offset) . "\n");
        }
}

probe kernel.function("sys_close")
{
        if (is_traced_call(execname())) {
                output_header("close", execname(), string(pid()));

                fd = get_fd($fd);
                print(" fd: " . string(fd) . "\n");
        }
}


function init_proc_fs() %{
        app_trace_proc_fs = register_sysctl_table(app_trace_root_table, 1);
%}

function deinit_proc_fs() %{
        unregister_sysctl_table(app_trace_proc_fs);
%}

probe begin
{
        log("trace-io: starting probe");
        init_proc_fs();
}

probe end
{
        log("trace-io: ending probe");
        deinit_proc_fs();
}

=======================================


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]