summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/autoconf-find-task-pid.c6
-rw-r--r--runtime/itrace.c56
-rw-r--r--runtime/loc2c-runtime.h25
-rw-r--r--runtime/staprun/common.c218
-rw-r--r--runtime/staprun/mainloop.c60
-rw-r--r--runtime/staprun/relay.c134
-rw-r--r--runtime/staprun/relay_old.c124
-rw-r--r--runtime/staprun/staprun.h29
-rw-r--r--runtime/sym.h1
-rw-r--r--runtime/task_finder.c34
-rw-r--r--runtime/task_finder_vma.c31
-rw-r--r--runtime/transport/control.c7
-rw-r--r--runtime/transport/transport.c20
-rw-r--r--runtime/transport/transport_msgs.h8
-rw-r--r--runtime/uprobes2/uprobes.c6
-rw-r--r--runtime/uprobes2/uprobes.h5
-rw-r--r--runtime/utrace_compatibility.h14
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;
}