diff options
author | Jim Keniston <jkenisto@us.ibm.com> | 2009-03-23 15:51:58 -0700 |
---|---|---|
committer | Jim Keniston <jkenisto@us.ibm.com> | 2009-03-23 15:51:58 -0700 |
commit | 1cd9c3ad40595180123083109e5b7d1230095f54 (patch) | |
tree | d1226de1275b40803f3e1c9d446232612b9a61a9 /runtime | |
parent | d8b7418ba4cf2bf2571f66a42517b9bced1b9132 (diff) | |
parent | d4db5608dbc31868a2041f20ea3f473eef3e61fd (diff) | |
download | systemtap-steved-1cd9c3ad40595180123083109e5b7d1230095f54.tar.gz systemtap-steved-1cd9c3ad40595180123083109e5b7d1230095f54.tar.xz systemtap-steved-1cd9c3ad40595180123083109e5b7d1230095f54.zip |
Merge branch 'master' of ssh://kenistoj@sources.redhat.com/git/systemtap
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/autoconf-find-task-pid.c | 6 | ||||
-rw-r--r-- | runtime/itrace.c | 56 | ||||
-rw-r--r-- | runtime/loc2c-runtime.h | 25 | ||||
-rw-r--r-- | runtime/staprun/common.c | 218 | ||||
-rw-r--r-- | runtime/staprun/mainloop.c | 60 | ||||
-rw-r--r-- | runtime/staprun/relay.c | 134 | ||||
-rw-r--r-- | runtime/staprun/relay_old.c | 124 | ||||
-rw-r--r-- | runtime/staprun/staprun.h | 29 | ||||
-rw-r--r-- | runtime/sym.h | 1 | ||||
-rw-r--r-- | runtime/task_finder.c | 34 | ||||
-rw-r--r-- | runtime/task_finder_vma.c | 31 | ||||
-rw-r--r-- | runtime/transport/control.c | 7 | ||||
-rw-r--r-- | runtime/transport/transport.c | 20 | ||||
-rw-r--r-- | runtime/transport/transport_msgs.h | 8 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 6 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 5 | ||||
-rw-r--r-- | runtime/utrace_compatibility.h | 14 |
17 files changed, 701 insertions, 77 deletions
diff --git a/runtime/autoconf-find-task-pid.c b/runtime/autoconf-find-task-pid.c new file mode 100644 index 00000000..549d5ac3 --- /dev/null +++ b/runtime/autoconf-find-task-pid.c @@ -0,0 +1,6 @@ +#include <linux/sched.h> + +void foo (pid_t k) { + struct task_struct *tsk = find_task_by_pid (k); + (void) tsk; +} diff --git a/runtime/itrace.c b/runtime/itrace.c index ed32b0bc..618cbff0 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -1,6 +1,7 @@ /* * user space instruction tracing * Copyright (C) 2005, 2006, 2007, 2008, 2009 IBM Corp. + * Copyright (C) 2009 Red Hat Inc. * * This file is part of systemtap, and is free software. You can * redistribute it and/or modify it under the terms of the GNU General @@ -17,8 +18,15 @@ #include <linux/sched.h> #include <linux/rcupdate.h> #include <linux/utrace.h> + +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #include <asm/string.h> #include "uprobes/uprobes.h" +#include "utrace_compatibility.h" #ifndef put_task_struct #define put_task_struct(t) \ @@ -55,7 +63,7 @@ struct itrace_info { struct list_head link; }; -static u32 debug = 1; +static u32 debug = 0 /* 1 */; static LIST_HEAD(usr_itrace_info); static spinlock_t itrace_lock; @@ -118,10 +126,15 @@ static int __access_process_vm(struct task_struct *tsk, unsigned long addr, void return buf - old_buf; } +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_quiesce(struct utrace_attached_engine *engine, + struct task_struct *tsk) +#else static u32 usr_itrace_report_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event) +#endif { int status; struct itrace_info *ui; @@ -129,10 +142,23 @@ static u32 usr_itrace_report_quiesce(enum utrace_resume_action action, ui = rcu_dereference(engine->data); WARN_ON(!ui); +#ifdef UTRACE_ORIG_VERSION + return (ui->step_flag); // XXX XXX XXX +#else return (event == 0 ? ui->step_flag : UTRACE_RESUME); +#endif } +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_signal( + struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs, + u32 action, siginfo_t *info, + const struct k_sigaction *orig_ka, + struct k_sigaction *return_ka) +#else static u32 usr_itrace_report_signal(u32 action, struct utrace_attached_engine *engine, struct task_struct *tsk, @@ -140,6 +166,7 @@ static u32 usr_itrace_report_signal(u32 action, siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) +#endif { struct itrace_info *ui; u32 return_flags; @@ -174,16 +201,31 @@ static u32 usr_itrace_report_signal(u32 action, return return_flags; } + + +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_clone( + struct utrace_attached_engine *engine, + struct task_struct *parent, + unsigned long clone_flags, + struct task_struct *child) +#else static u32 usr_itrace_report_clone(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) +#endif { return UTRACE_RESUME; } +#ifdef UTRACE_ORIG_VERSION +static u32 usr_itrace_report_death(struct utrace_attached_engine *e, + struct task_struct *tsk) +#else static u32 usr_itrace_report_death(struct utrace_attached_engine *e, struct task_struct *tsk, bool group_dead, int signal) +#endif { struct itrace_info *ui = rcu_dereference(e->data); WARN_ON(!ui); @@ -275,8 +317,13 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe struct itrace_info *ui; struct task_struct *tsk; + spin_lock_init(&itrace_lock); rcu_read_lock(); +#ifdef STAPCONF_FIND_TASK_PID + tsk = find_task_by_pid(tid); +#else tsk = find_task_by_vpid(tid); +#endif if (!tsk) { printk(KERN_ERR "usr_itrace_init: Cannot find process %d\n", tid); rcu_read_unlock(); @@ -293,11 +340,6 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe put_task_struct(tsk); rcu_read_unlock(); - spin_lock_init(&itrace_lock); - - /* set initial state */ - spin_lock(&itrace_lock); - spin_unlock(&itrace_lock); printk(KERN_INFO "usr_itrace_init: completed for tid = %d\n", tid); return 0; @@ -314,7 +356,6 @@ void static remove_usr_itrace_info(struct itrace_info *ui) if (debug) printk(KERN_INFO "remove_usr_itrace_info: tid=%d\n", ui->tid); - spin_lock(&itrace_lock); if (ui->tsk && ui->engine) { status = utrace_control(ui->tsk, ui->engine, UTRACE_DETACH); if (status < 0 && status != -ESRCH && status != -EALREADY) @@ -322,6 +363,7 @@ void static remove_usr_itrace_info(struct itrace_info *ui) "utrace_control(UTRACE_DETACH) returns %d\n", status); } + spin_lock(&itrace_lock); list_del(&ui->link); spin_unlock(&itrace_lock); kfree(ui); diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 0af19edc..16ddb950 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -186,37 +186,34 @@ */ #define kread(ptr) ({ \ - typeof(*(ptr)) _v; \ - if (probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ - DEREF_FAULT(ptr); \ + typeof(*(ptr)) _v = 0; \ + if (lookup_bad_addr((unsigned long)(ptr)) || \ + probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ + DEREF_FAULT(ptr); \ _v; \ }) #define kwrite(ptr, value) ({ \ typeof(*(ptr)) _v; \ _v = (typeof(*(ptr)))(value); \ - if (probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ - STORE_DEREF_FAULT(ptr); \ + if (lookup_bad_addr((unsigned long)addr) || \ + probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ + STORE_DEREF_FAULT(ptr); \ }) #define deref(size, addr) ({ \ - intptr_t _i; \ - if (lookup_bad_addr((unsigned long)addr)) \ - __deref_bad(); \ + intptr_t _i = 0; \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ case 4: _i = kread((u32 *)(addr)); break; \ case 8: _i = kread((u64 *)(addr)); break; \ default: __deref_bad(); \ - /* uninitialized _i should also be caught by -Werror */ \ } \ _i; \ }) #define store_deref(size, addr, value) ({ \ - if (lookup_bad_addr((unsigned long)addr)) \ - __store_deref_bad(); \ switch (size) { \ case 1: kwrite((u8 *)(addr), (value)); break; \ case 2: kwrite((u16 *)(addr), (value)); break; \ @@ -237,7 +234,7 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ u8 _b; u16 _w; u32 _l; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ @@ -277,7 +274,7 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ u8 _b; u16 _w; u32 _l; u64 _q; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ @@ -394,7 +391,7 @@ extern void __store_deref_bad(void); #define deref(size, addr) \ ({ \ int _bad = 0; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index fd16b4b8..8200ec9d 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -27,6 +27,9 @@ int attach_mod; int delete_mod; int load_only; int need_uprobes; +int daemon_mode; +off_t fsize_max; +int fnum_max; /* module variables */ char *modname = NULL; @@ -35,9 +38,132 @@ char *modoptions[MAXMODOPTIONS]; int control_channel = -1; /* NB: fd==0 possible */ +static char path_buf[PATH_MAX]; +static char *get_abspath(char *path) +{ + int len; + if (path[0] == '/') + return path; + + len = strlen(getcwd(path_buf, PATH_MAX)); + if (len + 2 + strlen(path) >= PATH_MAX) + return NULL; + path_buf[len] = '/'; + strcpy(&path_buf[len + 1], path); + return path_buf; +} + +int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t) +{ + char *c = buf; + const char *c2 = fmt, *end = buf + max; + int ret, num; + struct tm tm; + if (buf == NULL || fmt == NULL || max <= 1) + return -EINVAL; + localtime_r(&t, &tm); + + while (*c2 != '\0'){ + if (c + 1 >= end) + return -EINVAL; + if (*c2 != '%') { + *c++ = *c2++; + continue; + } + c2++; + switch (*c2++) { + case '%': + *c++ = '%'; + break; + case 'Y': + num = tm.tm_year + 1900; + goto numbering; + case 'y': + num = tm.tm_year % 100; + goto numbering02; + case 'C': + num = ((tm.tm_year + 1900 - 1) / 100) + 1; + goto numbering; + case 'm': + num = tm.tm_mon + 1; + goto numbering02; + case 'd': + num = tm.tm_mday; + goto numbering02; + case 'e': + num = tm.tm_mday; + goto numbering; + case 'F': + ret = snprintf(c, end - c, "%d-%02d-%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + if (ret < 0) return ret; + c += ret; + break; + case 'H': + num = tm.tm_hour; + goto numbering02; + case 'I': + num = tm.tm_hour % 12; + if (num == 0) num = 12; + goto numbering02; + case 'j': + ret = snprintf(c, end - c, "%03d", tm.tm_yday); + if (ret < 0) return ret; + c += ret; + break; + case 'k': + num = tm.tm_hour; + goto numbering; + case 'l': + num = tm.tm_hour % 12; + if (num == 0) num = 12; + goto numbering; + case 'M': + num = tm.tm_min; + goto numbering02; + case 'S': + num = tm.tm_sec; + goto numbering02; + case 'R': + ret = snprintf(c, end - c, "%02d:%02d", + tm.tm_hour, tm.tm_min); + if (ret < 0) return ret; + c += ret; + break; + case 'T': + ret = snprintf(c, end - c, "%02d:%02d:%02d", + tm.tm_hour, tm.tm_min, tm.tm_sec); + if (ret < 0) return ret; + c += ret; + break; + case 'u': + num = tm.tm_wday == 0 ? 7 : tm.tm_wday; + goto numbering; + case 'w': + num = tm.tm_wday; + goto numbering; + default: + return -EINVAL; + } + continue; +numbering: + ret = snprintf(c, end - c, "%d", num); + if (ret < 0) return ret; + c += ret; + continue; +numbering02: + ret = snprintf(c, end - c, "%02d", num); + if (ret < 0) return ret; + c += ret; + } + *c = '\0'; + return c - buf; +} + void parse_args(int argc, char **argv) { int c; + char *s; /* Initialize option variables. */ verbose = 0; @@ -49,8 +175,11 @@ void parse_args(int argc, char **argv) delete_mod = 0; load_only = 0; need_uprobes = 0; + daemon_mode = 0; + fsize_max = 0; + fnum_max = 0; - while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:")) != EOF) { + while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:S:D")) != EOF) { switch (c) { case 'u': need_uprobes = 1; @@ -85,11 +214,38 @@ void parse_args(int argc, char **argv) case 'L': load_only = 1; break; + case 'D': + daemon_mode = 1; + break; + case 'S': + fsize_max = strtoul(optarg, &s, 10); + fsize_max <<= 20; + if (s[0] == ',') + fnum_max = (int)strtoul(&s[1], &s, 10); + if (s[0] != '\0') { + err("Invalid file size option '%s'.\n", optarg); + usage(argv[0]); + } + break; default: usage(argv[0]); } } - + if (outfile_name) { + char tmp[PATH_MAX]; + int ret; + outfile_name = get_abspath(outfile_name); + if (outfile_name == NULL) { + err("File name is too long.\n"); + usage(argv[0]); + } + ret = stap_strfloctime(tmp, PATH_MAX - 18, /* = _cpuNNN.SSSSSSSSSS */ + outfile_name, time(NULL)); + if (ret < 0) { + err("Filename format is invalid or too long.\n"); + usage(argv[0]); + } + } if (attach_mod && load_only) { err("You can't specify the '-A' and '-L' options together.\n"); usage(argv[0]); @@ -118,18 +274,41 @@ void parse_args(int argc, char **argv) err("You can't specify the '-c' and '-x' options together.\n"); usage(argv[0]); } + + if (daemon_mode && load_only) { + err("You can't specify the '-D' and '-L' options together.\n"); + usage(argv[0]); + } + if (daemon_mode && delete_mod) { + err("You can't specify the '-D' and '-d' options together.\n"); + usage(argv[0]); + } + if (daemon_mode && target_cmd) { + err("You can't specify the '-D' and '-c' options together.\n"); + usage(argv[0]); + } + if (daemon_mode && outfile_name == NULL) { + err("You have to specify output FILE with '-D' option.\n"); + usage(argv[0]); + } + if (outfile_name == NULL && fsize_max != 0) { + err("You have to specify output FILE with '-S' option.\n"); + usage(argv[0]); + } } void usage(char *prog) { - err("\n%s [-v] [-c cmd ] [-x pid] [-u user]\n" - "\t[-A|-L] [-b bufsize] [-o FILE] MODULE [module-options]\n", prog); + err("\n%s [-v] [-c cmd ] [-x pid] [-u user] [-A|-L|-d]\n" + "\t[-b bufsize] [-o FILE [-D] [-S size[,N]]] MODULE [module-options]\n", prog); err("-v Increase verbosity.\n"); err("-c cmd Command \'cmd\' will be run and staprun will\n"); err(" exit when it does. The '_stp_target' variable\n"); err(" will contain the pid for the command.\n"); err("-x pid Sets the '_stp_target' variable to pid.\n"); - err("-o FILE Send output to FILE.\n"); + err("-o FILE Send output to FILE. This supports a subset of\n"); + err(" strftime(3) (%%%%,%%C,%%Y,%%y,%%m,%%d,%%e,%%F,%%H,%%I\n"); + err(" %%j,%%k,%%l,%%M,%%S,%%R,%%T,%%u,%%w) for FILE.\n"); err("-b buffer size The systemtap module specifies a buffer size.\n"); err(" Setting one here will override that value. The\n"); err(" value should be an integer between 1 and 4095 \n"); @@ -140,6 +319,14 @@ void usage(char *prog) err("-d Delete a module. Only detached or unused modules\n"); err(" the user has permission to access will be deleted. Use \"*\"\n"); err(" (quoted) to delete all unused modules.\n"); + err("-D Run in background. This requires '-o' option.\n"); + err("-S size[,N] Switches output file to next file when the size\n"); + err(" of file reaches the specified size. The value\n"); + err(" should be an integer greater than 1 which is\n"); + err(" assumed to be the maximum file size in MB.\n"); + err(" When the number of output files reaches N, it\n"); + err(" switches to the first output file. You can omit\n"); + err(" the second argument.\n"); err("MODULE can be either a module name or a module path. If a\n"); err("module name is used, it is looked for in the following\n"); err("directory: /lib/modules/`uname -r`/systemtap\n"); @@ -344,3 +531,24 @@ int send_request(int type, void *data, int len) if (rc < 0) return rc; return (rc != len+4); } + +#include <stdarg.h> + +static int use_syslog = 0; + +void eprintf(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + if (use_syslog) + vsyslog(LOG_ERR, fmt, va); + else + vfprintf(stderr, fmt, va); + va_end(va); +} + +void switch_syslog(const char *name) +{ + openlog(name, LOG_PID, LOG_DAEMON); + use_syslog = 1; +} diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 29eb4f1f..c80bbba4 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -318,6 +318,41 @@ int init_stapio(void) if (target_cmd) start_cmd(); + /* Run in background */ + if (daemon_mode) { + pid_t pid; + int ret; + dbug(2, "daemonizing stapio\n"); + + /* daemonize */ + ret = daemon(0, 1); /* don't close stdout at this time. */ + if (ret) { + err("Failed to daemonize stapio\n"); + return -1; + } + + /* change error messages to syslog. */ + switch_syslog("stapio"); + + /* show new pid */ + pid = getpid(); + fprintf(stdout, "%d\n", pid); + fflush(stdout); + + /* redirect all outputs to /dev/null */ + ret = open("/dev/null", O_RDWR); + if (ret < 0) { + err("Failed to open /dev/null\n"); + return -1; + } + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(ret, STDOUT_FILENO); + dup2(ret, STDERR_FILENO); + close(ret); + } + return 0; } @@ -454,21 +489,14 @@ int stp_main_loop(void) switch (type) { #ifdef STP_OLD_TRANSPORT case STP_REALTIME_DATA: - { - ssize_t bw = write(out_fd[0], data, nb); - if (bw >= 0 && bw != nb) { - nb = nb - bw; - bw = write(out_fd[0], data, nb); - } - if (bw != nb) { - _perr("write error (nb=%ld)", (long)nb); - cleanup_and_exit(0); - } - break; + if (write_realtime_data(data, nb)) { + _perr("write error (nb=%ld)", (long)nb); + cleanup_and_exit(0); } + break; #endif case STP_OOB_DATA: - fputs((char *)data, stderr); + eprintf("%s", (char *)data); break; case STP_EXIT: { @@ -477,6 +505,14 @@ int stp_main_loop(void) cleanup_and_exit(0); break; } + case STP_REQUEST_EXIT: + { + /* module asks us to start exiting, so send STP_EXIT */ + dbug(2, "got STP_REQUEST_EXIT\n"); + int32_t rc, btype = STP_EXIT; + rc = write(control_channel, &btype, sizeof(btype)); + break; + } case STP_START: { struct _stp_msg_start *t = (struct _stp_msg_start *)data; diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c index 19621933..50f295b5 100644 --- a/runtime/staprun/relay.c +++ b/runtime/staprun/relay.c @@ -17,6 +17,9 @@ static pthread_t reader[NR_CPUS]; static int relay_fd[NR_CPUS]; static int bulkmode = 0; static volatile int stop_threads = 0; +static time_t *time_backlog[NR_CPUS]; +static int backlog_order=0; +#define BACKLOG_MASK ((1 << backlog_order) - 1) /* * ppoll exists in glibc >= 2.4 @@ -44,6 +47,90 @@ static int ppoll(struct pollfd *fds, nfds_t nfds, } #endif +int init_backlog(int cpu) +{ + int order = 0; + if (!fnum_max) + return 0; + while (fnum_max >> order) order++; + if (fnum_max == 1<<(order-1)) order--; + time_backlog[cpu] = (time_t *)calloc(1<<order, sizeof(time_t)); + if (time_backlog[cpu] == NULL) { + _err("Memory allocation failed\n"); + return -1; + } + backlog_order = order; + return 0; +} + +void write_backlog(int cpu, int fnum, time_t t) +{ + time_backlog[cpu][fnum & BACKLOG_MASK] = t; +} + +time_t read_backlog(int cpu, int fnum) +{ + return time_backlog[cpu][fnum & BACKLOG_MASK]; +} + +int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t) +{ + int len; + len = stap_strfloctime(buf, max, outfile_name, t); + if (len < 0) { + err("Invalid FILE name format\n"); + return -1; + } + if (bulkmode) { + /* special case: for testing we sometimes want to write to /dev/null */ + if (strcmp(outfile_name, "/dev/null") == 0) { + strcpy(buf, "/dev/null"); + } else { + if (snprintf_chk(&buf[len], PATH_MAX - len, + "_cpu%d.%d", cpu, fnum)) + return -1; + } + } else { + /* stream mode */ + if (snprintf_chk(&buf[len], PATH_MAX - len, ".%d", fnum)) + return -1; + } + return 0; +} + +static int open_outfile(int fnum, int cpu, int remove_file) +{ + char buf[PATH_MAX]; + time_t t; + if (!outfile_name) { + _err("-S is set without -o. Please file a bug report.\n"); + return -1; + } + + time(&t); + if (fnum_max) { + if (remove_file) { + /* remove oldest file */ + if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, + cpu, read_backlog(cpu, fnum - fnum_max)) < 0) + return -1; + remove(buf); /* don't care */ + } + write_backlog(cpu, fnum, t); + } + + if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0) + return -1; + out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (out_fd[cpu] < 0) { + perr("Couldn't open output file %s", buf); + return -1; + } + if (set_clexec(out_fd[cpu]) < 0) + return -1; + return 0; +} + /** * reader_thread - per-cpu channel buffer reader */ @@ -57,6 +144,9 @@ static void *reader_thread(void *data) struct timespec tim = {.tv_sec=0, .tv_nsec=200000000}, *timeout = &tim; sigset_t sigs; struct sigaction sa; + off_t wsize = 0; + int fnum = 0; + int remove_file = 0; sigemptyset(&sigs); sigaddset(&sigs,SIGUSR2); @@ -99,6 +189,19 @@ static void *reader_thread(void *data) } } while ((rc = read(relay_fd[cpu], buf, sizeof(buf))) > 0) { + wsize += rc; + /* Switching file */ + if (fsize_max && wsize > fsize_max) { + close(out_fd[cpu]); + fnum++; + if (fnum_max && fnum == fnum_max) + remove_file = 1; + if (open_outfile(fnum, cpu, remove_file) < 0) { + perr("Couldn't open file for cpu %d, exiting.", cpu); + return(NULL); + } + wsize = 0; + } if (write(out_fd[cpu], buf, rc) != rc) { perr("Couldn't write to output %d for cpu %d, exiting.", out_fd[cpu], cpu); return(NULL); @@ -116,7 +219,7 @@ static void *reader_thread(void *data) */ int init_relayfs(void) { - int i; + int i, len; struct statfs st; char rqbuf[128]; char buf[PATH_MAX], relay_filebase[PATH_MAX]; @@ -163,14 +266,29 @@ int init_relayfs(void) return -1; } - if (bulkmode) { + if (fsize_max) { + /* switch file mode */ + for (i = 0; i < ncpus; i++) { + if (init_backlog(i) < 0) + return -1; + if (open_outfile(0, i, 0) < 0) + return -1; + } + } else if (bulkmode) { for (i = 0; i < ncpus; i++) { if (outfile_name) { /* special case: for testing we sometimes want to write to /dev/null */ if (strcmp(outfile_name, "/dev/null") == 0) { strcpy(buf, "/dev/null"); } else { - if (sprintf_chk(buf, "%s_%d", outfile_name, i)) + len = stap_strfloctime(buf, PATH_MAX, + outfile_name, time(NULL)); + if (len < 0) { + err("Invalid FILE name format\n"); + return -1; + } + if (snprintf_chk(&buf[len], + PATH_MAX - len, "_%d", i)) return -1; } } else { @@ -189,9 +307,15 @@ int init_relayfs(void) } else { /* stream mode */ if (outfile_name) { - out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666); + len = stap_strfloctime(buf, PATH_MAX, + outfile_name, time(NULL)); + if (len < 0) { + err("Invalid FILE name format\n"); + return -1; + } + out_fd[0] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); if (out_fd[0] < 0) { - perr("Couldn't open output file %s", outfile_name); + perr("Couldn't open output file %s", buf); return -1; } if (set_clexec(out_fd[i]) < 0) diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c index bd746f19..ef8fd0da 100644 --- a/runtime/staprun/relay_old.c +++ b/runtime/staprun/relay_old.c @@ -23,6 +23,14 @@ static int bulkmode = 0; unsigned subbuf_size = 0; unsigned n_subbufs = 0; +struct switchfile_ctrl_block { + off_t wsize; + int fnum; + int rmfile; +}; + +static struct switchfile_ctrl_block global_scb = {0, 0, 0}; + /* per-cpu buffer info */ static struct buf_status { @@ -70,6 +78,41 @@ void close_oldrelayfs(int detach) close_relayfs_files(i); } +static int open_oldoutfile(int fnum, int cpu, int remove_file) +{ + char buf[PATH_MAX]; + time_t t; + if (outfile_name) { + time(&t); + if (fnum_max) { + if (remove_file) { + /* remove oldest file */ + if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, + cpu, read_backlog(cpu, fnum - fnum_max)) < 0) + return -1; + remove(buf); /* don't care */ + } + write_backlog(cpu, fnum, t); + } + if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0) + return -1; + } else if (bulkmode) { + if (sprintf_chk(buf, "stpd_cpu%d.%d", cpu, fnum)) + return -1; + } else { /* stream mode */ + out_fd[cpu] = STDOUT_FILENO; + return 0; + } + + out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (out_fd[cpu] < 0) { + perr("Couldn't open output file %s", buf); + return -1; + } + if (set_clexec(out_fd[cpu]) < 0) + return -1; + return 0; +} /** * open_relayfs_files - open and mmap buffer and open output file. * Returns -1 on unexpected failure, 0 if file not found, 1 on success. @@ -104,18 +147,31 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p return -1; } + if (fsize_max) { + if (init_backlog(cpu) < 0) + goto err2; + if (open_oldoutfile(0, cpu, 0) < 0) + goto err2; + goto opened; + } if (outfile_name) { /* special case: for testing we sometimes want to * write to /dev/null */ if (strcmp(outfile_name, "/dev/null") == 0) { strcpy(tmp, "/dev/null"); } else { - if (sprintf_chk(tmp, "%s_%d", outfile_name, cpu)) - goto err1; + int len; + len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL)); + if (len < 0) { + err("Invalid FILE name format\n"); + goto err2; + } + if (snprintf_chk(&tmp[len], PATH_MAX - len, "_%d", cpu)) + goto err2; } } else { if (sprintf_chk(tmp, "stpd_cpu%d", cpu)) - goto err1; + goto err2; } if((percpu_tmpfile[cpu] = fopen(tmp, "w+")) == NULL) { @@ -126,6 +182,7 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p perr("Couldn't open output file %s", tmp); goto err2; } +opened: total_bufsize = subbuf_size * n_subbufs; relay_buffer[cpu] = mmap(NULL, total_bufsize, PROT_READ, @@ -155,7 +212,8 @@ err1: /** * process_subbufs - write ready subbufs to disk */ -static int process_subbufs(struct _stp_buf_info *info) +static int process_subbufs(struct _stp_buf_info *info, + struct switchfile_ctrl_block *scb) { unsigned subbufs_ready, start_subbuf, end_subbuf, subbuf_idx, i; int len, cpu = info->cpu; @@ -173,6 +231,18 @@ static int process_subbufs(struct _stp_buf_info *info) padding = *((unsigned *)subbuf_ptr); subbuf_ptr += sizeof(padding); len = (subbuf_size - sizeof(padding)) - padding; + scb->wsize += len; + if (fsize_max && scb->wsize > fsize_max) { + fclose(percpu_tmpfile[cpu]); + scb->fnum ++; + if (fnum_max && scb->fnum == fnum_max) + scb->rmfile = 1; + if (open_oldoutfile(scb->fnum, cpu, scb->rmfile) < 0) { + perr("Couldn't open file for cpu %d, exiting.", cpu); + exit(1); + } + scb->wsize = 0; + } if (len) { if (fwrite_unlocked (subbuf_ptr, len, 1, percpu_tmpfile[cpu]) != 1) { _perr("Couldn't write to output file for cpu %d, exiting:", cpu); @@ -196,6 +266,7 @@ static void *reader_thread(void *data) struct _stp_consumed_info consumed_info; unsigned subbufs_consumed; cpu_set_t cpu_mask; + struct switchfile_ctrl_block scb = {0, 0, 0}; CPU_ZERO(&cpu_mask); CPU_SET(cpu, &cpu_mask); @@ -217,7 +288,7 @@ static void *reader_thread(void *data) } rc = read(proc_fd[cpu], &status[cpu].info, sizeof(struct _stp_buf_info)); - subbufs_consumed = process_subbufs(&status[cpu].info); + subbufs_consumed = process_subbufs(&status[cpu].info, &scb); if (subbufs_consumed) { if (subbufs_consumed > status[cpu].max_backlog) status[cpu].max_backlog = subbufs_consumed; @@ -233,6 +304,33 @@ static void *reader_thread(void *data) } /** + * write_realtime_data - write realtime data packet to disk + */ +int write_realtime_data(void *data, ssize_t nb) +{ + ssize_t bw; + global_scb.wsize += nb; + if (fsize_max && global_scb.wsize > fsize_max) { + close(out_fd[0]); + global_scb.fnum++; + if (fnum_max && global_scb.fnum == fnum_max) + global_scb.rmfile = 1; + if (open_oldoutfile(global_scb.fnum, 0, + global_scb.rmfile) < 0) { + perr("Couldn't open file, exiting."); + return -1; + } + global_scb.wsize = 0; + } + bw = write(out_fd[0], data, nb); + if (bw >= 0 && bw != nb) { + nb = nb - bw; + bw = write(out_fd[0], data, nb); + } + return bw != nb; +} + +/** * init_relayfs - create files and threads for relayfs processing * * Returns 0 if successful, negative otherwise @@ -249,10 +347,22 @@ int init_oldrelayfs(void) bulkmode = 1; if (!bulkmode) { + int len; + char tmp[PATH_MAX]; + if (fsize_max) { + if (init_backlog(0)) + return -1; + return open_oldoutfile(0, 0, 0); + } if (outfile_name) { - out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666); + len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL)); + if (len < 0) { + err("Invalid FILE name format\n"); + return -1; + } + out_fd[0] = open (tmp, O_CREAT|O_TRUNC|O_WRONLY, 0666); if (out_fd[0] < 0 || set_clexec(out_fd[0]) < 0) { - perr("Couldn't open output file '%s'", outfile_name); + perr("Couldn't open output file '%s'", tmp); return -1; } } else diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 84cf63fc..acc533b2 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -9,7 +9,7 @@ * * Copyright (C) 2005-2008 Red Hat Inc. */ - +#define _FILE_OFFSET_BITS 64 #include <stdio.h> #include <stdlib.h> #include <ctype.h> @@ -33,31 +33,35 @@ #include <sys/wait.h> #include <sys/statfs.h> #include <linux/version.h> +#include <syslog.h> /* Include config.h to pick up dependency for --prefix usage. */ #include "config.h" -#define dbug(level, args...) {if (verbose>=level) {fprintf(stderr,"%s:%s:%d ",__name__,__FUNCTION__, __LINE__); fprintf(stderr,args);}} +extern void eprintf(const char *fmt, ...); +extern void switch_syslog(const char *name); + +#define dbug(level, args...) do {if (verbose>=level) {eprintf("%s:%s:%d ",__name__,__FUNCTION__, __LINE__); eprintf(args);}} while (0) extern char *__name__; /* print to stderr */ -#define err(args...) fprintf(stderr,args) +#define err(args...) eprintf(args) /* better perror() */ #define perr(args...) do { \ int _errno = errno; \ - fputs("ERROR: ", stderr); \ - fprintf(stderr, args); \ - fprintf(stderr, ": %s\n", strerror(_errno)); \ + eprintf("ERROR: "); \ + eprintf(args); \ + eprintf(": %s\n", strerror(_errno)); \ } while (0) /* Error messages. Use these for serious errors, not informational messages to stderr. */ -#define _err(args...) do {fprintf(stderr,"%s:%s:%d: ERROR: ",__name__, __FUNCTION__, __LINE__); fprintf(stderr,args);} while(0) +#define _err(args...) do {eprintf("%s:%s:%d: ERROR: ",__name__, __FUNCTION__, __LINE__); eprintf(args);} while(0) #define _perr(args...) do { \ int _errno = errno; \ _err(args); \ - fprintf(stderr, ": %s\n", strerror(_errno)); \ + eprintf(": %s\n", strerror(_errno)); \ } while (0) #define overflow_error() _err("Internal buffer overflow. Please file a bug report.\n") @@ -113,7 +117,12 @@ int init_relayfs(void); void close_relayfs(void); int init_oldrelayfs(void); void close_oldrelayfs(int); +int write_realtime_data(void *data, ssize_t nb); void setup_signals(void); +int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t); +int init_backlog(int cpu); +void write_backlog(int cpu, int fnum, time_t t); +time_t read_backlog(int cpu, int fnum); /* staprun_funcs.c */ void setup_staprun_signals(void); const char *moderror(int err); @@ -125,6 +134,7 @@ void start_symbol_thread(void); void stop_symbol_thread(void); /* common.c functions */ +int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t); void parse_args(int argc, char **argv); void usage(char *prog); void parse_modpath(const char *); @@ -153,6 +163,9 @@ extern int attach_mod; extern int delete_mod; extern int load_only; extern int need_uprobes; +extern int daemon_mode; +extern off_t fsize_max; +extern int fnum_max; /* getopt variables */ extern char *optarg; diff --git a/runtime/sym.h b/runtime/sym.h index e642cab4..586b10ca 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -25,6 +25,7 @@ struct _stp_section { struct _stp_module { const char* name; + const char* path; /* canonical path used for runtime matching. */ struct _stp_section *sections; unsigned num_sections; diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 9db713c3..3f4908cb 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -6,6 +6,12 @@ #endif #include <linux/utrace.h> + +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #include <linux/list.h> #include <linux/binfmts.h> #include <linux/mount.h> @@ -55,7 +61,6 @@ typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt, unsigned long vm_end, unsigned long vm_pgoff); -#ifdef DEBUG_TASK_FINDER_VMA static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, @@ -63,21 +68,32 @@ static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, unsigned long vm_end, unsigned long vm_pgoff) { + int i; +#ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "vm_cb: tsk %d:%d path %s, start 0x%08lx, end 0x%08lx, offset 0x%lx\n", tsk->pid, map_p, vm_path, vm_start, vm_end, vm_pgoff); +#endif if (map_p) { - // FIXME: What should we do with vm_path? We can't save - // the vm_path pointer itself, but we don't have any - // storage space allocated to save it in... - stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff); + struct _stp_module *module = NULL; + if (vm_path != NULL) + for (i = 0; i < _stp_num_modules; i++) + if (strcmp(vm_path, _stp_modules[i]->path) == 0) + { +#ifdef DEBUG_TASK_FINDER_VMA + _stp_dbug(__FUNCTION__, __LINE__, + "vm_cb: matched path %s to module\n", vm_path); +#endif + module = _stp_modules[i]; + break; + } + stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff, module); } else { stap_remove_vma_map_info(tsk, vm_start, vm_end, vm_pgoff); } return 0; } -#endif struct stap_task_finder_target { /* private: */ @@ -1016,6 +1032,7 @@ __stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action, static void __stp_call_vm_callbacks_with_vma(struct stap_task_finder_target *tgt, struct task_struct *tsk, + int map_p, struct vm_area_struct *vma) { char *mmpath_buf; @@ -1042,7 +1059,7 @@ __stp_call_vm_callbacks_with_vma(struct stap_task_finder_target *tgt, rc, (int)tsk->pid); } else { - __stp_call_vm_callbacks(tgt, tsk, 1, mmpath, + __stp_call_vm_callbacks(tgt, tsk, map_p, mmpath, vma->vm_start, vma->vm_end, (vma->vm_pgoff << PAGE_SHIFT)); } @@ -1135,7 +1152,7 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, down_read(&mm->mmap_sem); vma = __stp_find_file_based_vma(mm, rv); if (vma != NULL) { - __stp_call_vm_callbacks_with_vma(tgt, tsk, vma); + __stp_call_vm_callbacks_with_vma(tgt, tsk, 0, vma); } up_read(&mm->mmap_sem); mmput(mm); @@ -1208,6 +1225,7 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, && vma->vm_end <= entry->vm_end) { __stp_call_vm_callbacks_with_vma(tgt, tsk, + 1, vma); if (vma->vm_end >= entry->vm_end) break; diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c index 4dce4be8..83b206e5 100644 --- a/runtime/task_finder_vma.c +++ b/runtime/task_finder_vma.c @@ -25,6 +25,9 @@ struct __stp_tf_vma_entry { unsigned long vm_end; unsigned long vm_pgoff; // Is that enough? Should we store a dcookie for vm_file? + + // Module that this vma entry is mapped from, if any. + struct _stp_module *module; }; static struct __stp_tf_vma_entry @@ -200,7 +203,6 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk, hlist_for_each_entry(entry, node, head, hlist) { if (tsk->pid == entry->pid && vm_start == entry->addr) { - mutex_unlock(&__stp_tf_vma_mutex); return entry; } } @@ -211,7 +213,8 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk, // Add the vma info to the vma map hash table. static int stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start, - unsigned long vm_end, unsigned long vm_pgoff) + unsigned long vm_end, unsigned long vm_pgoff, + struct _stp_module *module) { struct hlist_head *head; struct hlist_node *node; @@ -242,6 +245,7 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start, entry->vm_start = vm_start; entry->vm_end = vm_end; entry->vm_pgoff = vm_pgoff; + entry->module = module; head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)]; hlist_add_head(&entry->hlist, head); @@ -305,3 +309,26 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr, mutex_unlock(&__stp_tf_vma_mutex); return rc; } + +// Get vma_entry of the address (vm_start/vm_end) if the vma is +// present in the vma hash table containing. +// Returns NULL if not present. +static struct __stp_tf_vma_entry * +__stp_tf_get_vma_entry_addr(struct task_struct *tsk, unsigned long addr) +{ + struct hlist_head *head; + struct hlist_node *node; + struct __stp_tf_vma_entry *entry; + + mutex_lock(&__stp_tf_vma_mutex); + head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)]; + hlist_for_each_entry(entry, node, head, hlist) { + if (tsk->pid == entry->pid + && addr >= entry->vm_start && addr < entry->vm_end) { + mutex_unlock(&__stp_tf_vma_mutex); + return entry; + } + } + mutex_unlock(&__stp_tf_vma_mutex); + return NULL; +} diff --git a/runtime/transport/control.c b/runtime/transport/control.c index edde244d..680d7306 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -13,6 +13,8 @@ static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static DEFINE_SPINLOCK(_stp_ctl_ready_lock); +static void _stp_cleanup_and_exit(int send_exit); + static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { u32 type; @@ -46,7 +48,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz } break; case STP_EXIT: - _stp_exit_flag = 1; + _stp_cleanup_and_exit(1); break; case STP_BULK: #ifdef STP_BULKMODE @@ -93,6 +95,9 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; + case STP_REQUEST_EXIT: + _dbug("sending STP_REQUEST_EXIT\n"); + break; default: _dbug("ERROR: unknown message type: %d\n", type); break; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7fcebd42..762c0a92 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -25,7 +25,6 @@ static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; static int _stp_probes_started = 0; static pid_t _stp_target = 0; -static int _stp_exit_called = 0; static int _stp_exit_flag = 0; #include "control.h" #ifdef STP_OLD_TRANSPORT @@ -89,13 +88,14 @@ static void _stp_handle_start(struct _stp_msg_start *st) /* when someone does /sbin/rmmod on a loaded systemtap module. */ static void _stp_cleanup_and_exit(int send_exit) { - if (!_stp_exit_called) { + static int called = 0; + if (!called) { int failures; dbug_trans(1, "cleanup_and_exit (%d)\n", send_exit); _stp_exit_flag = 1; /* we only want to do this stuff once */ - _stp_exit_called = 1; + called = 1; if (_stp_probes_started) { dbug_trans(1, "calling probe_exit\n"); @@ -119,6 +119,18 @@ static void _stp_cleanup_and_exit(int send_exit) } } +static void _stp_request_exit(void) +{ + static int called = 0; + if (!called) { + /* we only want to do this once */ + called = 1; + dbug_trans(1, "ctl_send STP_REQUEST_EXIT\n"); + _stp_ctl_send(STP_REQUEST_EXIT, NULL, 0); + dbug_trans(1, "done with ctl_send STP_REQUEST_EXIT\n"); + } +} + /* * Called when stapio closes the control channel. */ @@ -169,7 +181,7 @@ static void _stp_work_queue(void *data) /* if exit flag is set AND we have finished with probe_start() */ if (unlikely(_stp_exit_flag && _stp_probes_started)) - _stp_cleanup_and_exit(1); + _stp_request_exit(); if (likely(_stp_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 596f4925..0d9a5983 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -21,19 +21,20 @@ struct _stp_trace { enum { STP_START, - STP_EXIT, + STP_EXIT, STP_OOB_DATA, STP_SYSTEM, STP_TRANSPORT, STP_CONNECT, - STP_DISCONNECT, + STP_DISCONNECT, STP_BULK, STP_READY, - STP_RELOCATION, + STP_RELOCATION, /** deprecated STP_OLD_TRANSPORT **/ STP_BUF_INFO, STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, + STP_REQUEST_EXIT, STP_MAX_CMD }; @@ -52,6 +53,7 @@ static const char *_stp_command_name[] = { "STP_BUF_INFO", "STP_SUBBUFS_CONSUMED", "STP_REALTIME_DATA", + "STP_REQUEST_EXIT", }; #endif /* DEBUG_TRANS */ diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index af187fc9..a0e9f2fe 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -29,6 +29,12 @@ #include <linux/utrace.h> #include <linux/regset.h> #define UPROBES_IMPLEMENTATION 1 + +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #include "uprobes.h" #include <linux/tracehook.h> #include <linux/mm.h> diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index 11d01f5c..112e29e2 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -23,6 +23,11 @@ #include <linux/types.h> #include <linux/list.h> +/* Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + struct pt_regs; enum uprobe_type { diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h index 00b841d2..5521a5c2 100644 --- a/runtime/utrace_compatibility.h +++ b/runtime/utrace_compatibility.h @@ -1,6 +1,6 @@ /* * utrace compatibility defines and inlines - * Copyright (C) 2008 Red Hat Inc. + * Copyright (C) 2008-2009 Red Hat Inc. * * This file is part of systemtap, and is free software. You can * redistribute it and/or modify it under the terms of the GNU General @@ -13,6 +13,11 @@ #include <linux/utrace.h> +/* PR9974: Adapt to struct renaming. */ +#ifdef UTRACE_API_VERSION +#define utrace_attached_engine utrace_engine +#endif + #ifdef UTRACE_ACTION_RESUME /* @@ -28,6 +33,8 @@ enum utrace_resume_action { UTRACE_STOP = UTRACE_ACTION_QUIESCE, UTRACE_RESUME = UTRACE_ACTION_RESUME, UTRACE_DETACH = UTRACE_ACTION_DETACH, + UTRACE_SINGLESTEP = UTRACE_ACTION_SINGLESTEP, + UTRACE_BLOCKSTEP = UTRACE_ACTION_BLOCKSTEP, }; static inline struct utrace_attached_engine * @@ -48,6 +55,11 @@ utrace_control(struct task_struct *target, case UTRACE_STOP: return utrace_set_flags(target, engine, (engine->flags | UTRACE_ACTION_QUIESCE)); + case UTRACE_SINGLESTEP: + case UTRACE_BLOCKSTEP: + return utrace_set_flags(target, engine, + engine->flags | action); + default: return -EINVAL; } |