summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog51
-rw-r--r--runtime/ChangeLog29
-rw-r--r--runtime/syscall.h22
-rw-r--r--runtime/task_finder.c199
-rw-r--r--runtime/utrace_compatibility.h57
-rwxr-xr-xstap-client94
-rwxr-xr-xstap-server17
-rwxr-xr-xstap-serverd6
-rw-r--r--tapsets.cxx80
9 files changed, 447 insertions, 108 deletions
diff --git a/ChangeLog b/ChangeLog
index e191b9c9..2c89bb60 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,54 @@
+2008-08-21 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (itrace_derived_probe_group::emit_module_decls):
+ Updated task finder callback function signature.
+ (utrace_derived_probe_group::emit_module_decls): Ditto.
+
+2008-08-20 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (utrace_derived_probe_group::emit_probe_decl):
+ Supports original and new utrace interfaces.
+ (utrace_derived_probe_group::emit_module_decls): Ditto.
+
+2008-08-20 Dave Brolley <brolley@redhat.com>
+
+ * stap-client: Ignore SIGHUP and SIGPIPE.
+ (initialization): Set b_specified.:
+ (parse_options): Handle the -b option. Quote $stap_arg. Use process_m.
+ (process_m): New function.
+ (process_o): Set stdout_redirection to simply the filename.
+ (process_response): Obtain the exit code from stap on the server side.
+ Copy the module to the current directory if -m was specified.
+ Call stream_output.
+ (stream_output): It's back.
+ (maybe_call_staprun): Print status messages for -v. Leave v_level
+ unchanged. Pass -o option to staprun. Wait until the staprun job
+ disappears.
+ (terminate): Redirect message to stderr.
+ (interrupt): Only kill staprun if it's still running. Call cleanup
+ if exiting.
+ (ignore_signal): New function.
+ * stap-server (receive_request): Quote the job specifier.
+ (send_response): Likewise.
+ (read_data_file): Use read to check the first line. Use cat the read
+ the entire file.
+ * stap-serverd (listen): Quote job specifier.
+ (terminate): Likewise.
+
+2008-08-19 David Smith <dsmith@redhat.com>
+
+ PR 6841
+ * tapsets.cxx (utrace_derived_probe_group::emit_probe_decl):
+ Workaround utrace bug by quiescing threads before attaching a
+ utrace syscall engine to them.
+ (utrace_derived_probe_group::emit_module_decls): Emit quiesce
+ handler.
+
+2008-08-18 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (register_standard_tapsets): Add missing
+ 'process.syscall' and 'process.syscall.return' bindings.
+
2008-08-16 Mark Wielaard <mjw@redhat.com>
* configure.ac (build_elfutils): Mention possible distro
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 58678de5..3e1e400a 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,32 @@
+2008-08-21 David Smith <dsmith@redhat.com>
+
+ * task_finder.c (__stp_tf_vm_cb): Added task finder target
+ parameter.
+ (__stp_utrace_attach_match_filename): Updated task finder callback
+ call.
+ (__stp_utrace_task_finder_target_death): Ditto.
+ (__stp_utrace_task_finder_target_quiesce): Ditto.
+ (__stp_target_call_vm_callback): Ditto.
+ (__stp_utrace_task_finder_target_syscall_exit): Ditto.
+ (stap_start_task_finder): Ditto.
+
+2008-08-20 David Smith <dsmith@redhat.com>
+
+ * task_finder.c: Supports original and new utrace interfaces.
+ * utrace_compatibility.h (utrace_attach_task): Compatibility layer
+ for original utrace interface.
+
+ * task_finder.c (__stp_utrace_task_finder_target_syscall_entry):
+ Handles mmap2 (as well as mmap).
+ (__stp_utrace_task_finder_target_syscall_exit): Ditto.
+ * syscall.h: Added defines for mmap and mmap2.
+
+2008-08-19 David Smith <dsmith@redhat.com>
+
+ PR 6841
+ * task_finder.c (__stp_utrace_task_finder_target_quiesce):
+ Quiesces thread before turning on syscall tracing.
+
2008-08-14 Frank Ch. Eigler <fche@elastic.org>
PR 6842.
diff --git a/runtime/syscall.h b/runtime/syscall.h
index 3d1034e6..24e93463 100644
--- a/runtime/syscall.h
+++ b/runtime/syscall.h
@@ -11,12 +11,14 @@
#define _SYSCALL_H_
#if defined(__i386__) || defined(CONFIG_IA32_EMULATION)
-#define __MMAP_SYSCALL_NO_IA32 192 /* mmap2 */
+#define __MMAP_SYSCALL_NO_IA32 90
+#define __MMAP2_SYSCALL_NO_IA32 192
#define __MPROTECT_SYSCALL_NO_IA32 125
#define __MUNMAP_SYSCALL_NO_IA32 91
#define __MREMAP_SYSCALL_NO_IA32 163
# if !defined(CONFIG_IA32_EMULATION)
#define MMAP_SYSCALL_NO(tsk) __MMAP_SYSCALL_NO_IA32
+#define MMAP2_SYSCALL_NO(tsk) __MMAP2_SYSCALL_NO_IA32
#define MPROTECT_SYSCALL_NO(tsk) __MPROTECT_SYSCALL_NO_IA32
#define MUNMAP_SYSCALL_NO(tsk) __MUNMAP_SYSCALL_NO_IA32
#define MREMAP_SYSCALL_NO(tsk) __MREMAP_SYSCALL_NO_IA32
@@ -25,13 +27,19 @@
#if defined(__x86_64__)
#define __MMAP_SYSCALL_NO_X86_64 9
+/* x86_64 doesn't have a mmap2 system call. So, we'll use a number
+ * that doesn't map to a real system call. */
+#define __MMAP2_SYSCALL_NO_X86_64 ((unsigned long)-1)
#define __MPROTECT_SYSCALL_NO_X86_64 10
#define __MUNMAP_SYSCALL_NO_X86_64 11
#define __MREMAP_SYSCALL_NO_X86_64 25
# if defined(CONFIG_IA32_EMULATION)
-#define MMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \
- ? __MMAP_SYSCALL_NO_IA32 \
+#define MMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \
+ ? __MMAP_SYSCALL_NO_IA32 \
: __MMAP_SYSCALL_NO_X86_64)
+#define MMAP2_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \
+ ? __MMAP2_SYSCALL_NO_IA32 \
+ : __MMAP2_SYSCALL_NO_X86_64)
#define MPROTECT_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \
? __MPROTECT_SYSCALL_NO_IA32 \
: __MPROTECT_SYSCALL_NO_X86_64)
@@ -51,13 +59,17 @@
#if defined(__powerpc__)
#define MMAP_SYSCALL_NO(tsk) 90
+/* MMAP2 only exists on a 32-bit kernel. On a 64-bit kernel, we'll
+ * never see mmap2 (but that's OK). */
+#define MMAP2_SYSCALL_NO(tsk) 192
#define MPROTECT_SYSCALL_NO(tsk) 125
#define MUNMAP_SYSCALL_NO(tsk) 91
#define MREMAP_SYSCALL_NO(tsk) 163
#endif
-#if !defined(MMAP_SYSCALL_NO) || !defined(MPROTECT_SYSCALL_NO) \
- || !defined(MUNMAP_SYSCALL_NO) || !defined(MREMAP_SYSCALL_NO)
+#if !defined(MMAP_SYSCALL_NO) || !defined(MMAP2_SYSCALL_NO) \
+ || !defined(MPROTECT_SYSCALL_NO) || !defined(MUNMAP_SYSCALL_NO) \
+ || !defined(MREMAP_SYSCALL_NO)
#error "Unimplemented architecture"
#endif
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 59b83b76..146ce06f 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -11,6 +11,7 @@
#include <linux/mount.h>
#include "syscall.h"
+#include "utrace_compatibility.h"
#include "task_finder_vma.c"
static LIST_HEAD(__stp_task_finder_list);
@@ -36,19 +37,21 @@ atomic_t __stp_attach_count = ATOMIC_INIT (0);
#define debug_task_finder_report() /* empty */
#endif
-typedef int (*stap_task_finder_callback)(struct task_struct *tsk,
+typedef int (*stap_task_finder_callback)(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
int register_p,
- int process_p,
- struct stap_task_finder_target *tgt);
+ int process_p);
-typedef int (*stap_task_finder_vm_callback)(struct task_struct *tsk,
+typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
int map_p, char *vm_path,
unsigned long vm_start,
unsigned long vm_end,
unsigned long vm_pgoff);
#ifdef DEBUG_TASK_FINDER_VMA
-int __stp_tf_vm_cb(struct task_struct *tsk,
+int __stp_tf_vm_cb(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
int map_p, char *vm_path,
unsigned long vm_start,
unsigned long vm_end,
@@ -86,23 +89,54 @@ struct stap_task_finder_target {
stap_task_finder_vm_callback vm_callback;
};
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
struct task_struct *tsk);
+#else
+static u32
+__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ bool group_dead, int signal);
+#endif
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine,
struct task_struct *tsk);
+#else
+static u32
+__stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ unsigned long event);
+#endif
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *engine,
struct task_struct *tsk,
struct pt_regs *regs);
+#else
+static u32
+__stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs);
+#endif
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engine,
struct task_struct *tsk,
struct pt_regs *regs);
+#else
+static u32
+__stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs);
+#endif
static int
stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
@@ -186,11 +220,11 @@ stap_utrace_detach(struct task_struct *tsk,
// we'd miss detaching from it if we were checking to see if
// it had an mm.
- engine = utrace_attach(tsk, UTRACE_ATTACH_MATCH_OPS, ops, 0);
+ engine = utrace_attach_task(tsk, UTRACE_ATTACH_MATCH_OPS, ops, 0);
if (IS_ERR(engine)) {
rc = -PTR_ERR(engine);
if (rc != ENOENT) {
- _stp_error("utrace_attach returned error %d on pid %d",
+ _stp_error("utrace_attach_task returned error %d on pid %d",
rc, tsk->pid);
}
else {
@@ -203,7 +237,7 @@ stap_utrace_detach(struct task_struct *tsk,
rc = EFAULT;
}
else {
- rc = utrace_detach(tsk, engine);
+ rc = utrace_control(tsk, engine, UTRACE_DETACH);
switch (rc) {
case 0: /* success */
debug_task_finder_detach();
@@ -327,8 +361,8 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
| UTRACE_EVENT(SYSCALL_ENTRY) \
| UTRACE_EVENT(SYSCALL_EXIT))
-#define __STP_ATTACHED_TASK_VM_EVENTS (__STP_ATTACHED_TASK_VM_BASE_EVENTS \
- | UTRACE_ACTION_QUIESCE \
+#define __STP_ATTACHED_TASK_VM_EVENTS (__STP_ATTACHED_TASK_BASE_EVENTS \
+ | UTRACE_STOP \
| UTRACE_EVENT(QUIESCE))
#define __STP_ATTACHED_TASK_EVENTS(tgt) \
@@ -354,7 +388,7 @@ stap_utrace_attach(struct task_struct *tsk,
return EPERM;
mmput(mm);
- engine = utrace_attach(tsk, UTRACE_ATTACH_CREATE, ops, data);
+ engine = utrace_attach_task(tsk, UTRACE_ATTACH_CREATE, ops, data);
if (IS_ERR(engine)) {
int error = -PTR_ERR(engine);
if (error != ENOENT) {
@@ -369,11 +403,11 @@ stap_utrace_attach(struct task_struct *tsk,
rc = EFAULT;
}
else {
- rc = utrace_set_flags(tsk, engine, event_flags);
+ rc = utrace_set_events(tsk, engine, event_flags);
if (rc == 0)
debug_task_finder_attach();
else
- _stp_error("utrace_set_flags returned error %d on pid %d",
+ _stp_error("utrace_set_events returned error %d on pid %d",
rc, (int)tsk->pid);
}
return rc;
@@ -421,8 +455,9 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
continue;
if (cb_tgt->callback != NULL) {
- int rc = cb_tgt->callback(tsk, register_p,
- process_p, cb_tgt);
+ int rc = cb_tgt->callback(cb_tgt, tsk,
+ register_p,
+ process_p);
if (rc != 0) {
_stp_error("callback for %d failed: %d",
(int)tsk->pid, rc);
@@ -505,11 +540,20 @@ __stp_utrace_attach_match_tsk(struct task_struct *path_tsk,
return;
}
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine,
struct task_struct *parent,
unsigned long clone_flags,
struct task_struct *child)
+#else
+static u32
+__stp_utrace_task_finder_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
{
int rc;
struct mm_struct *mm;
@@ -517,24 +561,34 @@ __stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine,
char *mmpath;
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING)
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
// On clone, attach to the child.
rc = stap_utrace_attach(child, engine->ops, 0,
__STP_TASK_FINDER_EVENTS);
if (rc != 0 && rc != EPERM)
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
__stp_utrace_attach_match_tsk(parent, child, 1,
(clone_flags & CLONE_THREAD) == 0);
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
}
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine,
struct task_struct *tsk,
const struct linux_binprm *bprm,
struct pt_regs *regs)
+#else
+static u32
+__stp_utrace_task_finder_report_exec(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ const struct linux_binfmt *fmt,
+ const struct linux_binprm *bprm,
+ struct pt_regs *regs)
+#endif
{
size_t filelen;
struct list_head *tgt_node;
@@ -542,7 +596,7 @@ __stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine,
int found_node = 0;
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING)
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
// When exec'ing, we need to let callers detach from the
// parent thread (if necessary). For instance, assume
@@ -565,26 +619,40 @@ __stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine,
// relative.
__stp_utrace_attach_match_tsk(tsk, tsk, 1, 1);
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
}
+#ifdef UTRACE_ORIG_VERSION
static u32
stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine,
struct task_struct *tsk)
+#else
+static u32
+stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ bool group_dead, int signal)
+#endif
{
debug_task_finder_detach();
- return UTRACE_ACTION_DETACH;
+ return UTRACE_DETACH;
}
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
struct task_struct *tsk)
+#else
+static u32
+__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ bool group_dead, int signal)
+#endif
{
struct stap_task_finder_target *tgt = engine->data;
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
debug_task_finder_detach();
- return UTRACE_ACTION_DETACH;
+ return UTRACE_DETACH;
}
// The first implementation of this added a
@@ -600,30 +668,42 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
int rc;
// Call the callback
- rc = tgt->callback(tsk, 0,
- (tsk->signal == NULL) || (atomic_read(&tsk->signal->live) == 0),
- tgt);
+ rc = tgt->callback(tgt, tsk, 0,
+ ((tsk->signal == NULL)
+ || (atomic_read(&tsk->signal->live) == 0)));
if (rc != 0) {
_stp_error("death callback for %d failed: %d",
(int)tsk->pid, rc);
}
}
debug_task_finder_detach();
- return UTRACE_ACTION_DETACH;
+ return UTRACE_DETACH;
}
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine,
struct task_struct *tsk)
+#else
+static u32
+__stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ unsigned long event)
+#endif
{
struct stap_task_finder_target *tgt = engine->data;
+ int rc;
- // Turn off quiesce handling.
- utrace_set_flags(tsk, engine, __STP_ATTACHED_TASK_VM_BASE_EVENTS);
+ // Turn off quiesce handling (and turn on syscall handling).
+ rc = utrace_set_events(tsk, engine, __STP_ATTACHED_TASK_VM_BASE_EVENTS);
+ if (rc != 0)
+ _stp_error("utrace_set_events returned error %d on pid %d",
+ rc, (int)tsk->pid);
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
debug_task_finder_detach();
- return UTRACE_ACTION_DETACH;
+ return UTRACE_DETACH;
}
if (tgt != NULL && tgt->vm_callback != NULL) {
@@ -661,7 +741,8 @@ __stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine,
#endif
if (mmpath) {
// Call the callback
- rc = tgt->vm_callback(tsk, 1, mmpath,
+ rc = tgt->vm_callback(tgt, tsk, 1,
+ mmpath,
vma->vm_start,
vma->vm_end,
(vma->vm_pgoff
@@ -685,7 +766,7 @@ __stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine,
}
utftq_out:
- return (UTRACE_ACTION_NEWSTATE | UTRACE_ACTION_RESUME);
+ return UTRACE_RESUME;
}
@@ -702,10 +783,18 @@ __stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr)
return vma;
}
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *engine,
struct task_struct *tsk,
struct pt_regs *regs)
+#else
+static u32
+__stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs)
+#endif
{
struct stap_task_finder_target *tgt = engine->data;
unsigned long syscall_no;
@@ -716,20 +805,21 @@ __stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *eng
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
debug_task_finder_detach();
- return UTRACE_ACTION_DETACH;
+ return UTRACE_DETACH;
}
if (tgt == NULL || tgt->vm_callback == NULL)
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
// See if syscall is one we're interested in.
//
// FIXME: do we need to handle mremap()?
syscall_no = __stp_user_syscall_nr(regs);
if (syscall_no != MMAP_SYSCALL_NO(tsk)
+ && syscall_no != MMAP2_SYSCALL_NO(tsk)
&& syscall_no != MPROTECT_SYSCALL_NO(tsk)
&& syscall_no != MUNMAP_SYSCALL_NO(tsk))
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
// We need the first syscall argument to see what address
@@ -755,7 +845,7 @@ __stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *eng
mmput(mm);
}
}
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
}
static void
@@ -787,7 +877,7 @@ __stp_target_call_vm_callback(struct stap_task_finder_target *tgt,
rc, (int)tsk->pid);
}
else {
- rc = tgt->vm_callback(tsk, 1, mmpath, vma->vm_start,
+ rc = tgt->vm_callback(tgt, tsk, 1, mmpath, vma->vm_start,
vma->vm_end,
(vma->vm_pgoff << PAGE_SHIFT));
if (rc != 0) {
@@ -798,10 +888,18 @@ __stp_target_call_vm_callback(struct stap_task_finder_target *tgt,
_stp_kfree(mmpath_buf);
}
+#ifdef UTRACE_ORIG_VERSION
static u32
__stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engine,
struct task_struct *tsk,
struct pt_regs *regs)
+#else
+static u32
+__stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs)
+#endif
{
struct stap_task_finder_target *tgt = engine->data;
unsigned long syscall_no;
@@ -814,27 +912,28 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
debug_task_finder_detach();
- return UTRACE_ACTION_DETACH;
+ return UTRACE_DETACH;
}
if (tgt == NULL || tgt->vm_callback == NULL)
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
// See if syscall is one we're interested in.
//
// FIXME: do we need to handle mremap()?
syscall_no = __stp_user_syscall_nr(regs);
if (syscall_no != MMAP_SYSCALL_NO(tsk)
+ && syscall_no != MMAP2_SYSCALL_NO(tsk)
&& syscall_no != MPROTECT_SYSCALL_NO(tsk)
&& syscall_no != MUNMAP_SYSCALL_NO(tsk))
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
// Get return value
rv_addr = __stp_user_syscall_return_value(tsk, regs);
if ((rc = __stp_get_user(rv, rv_addr)) != 0) {
_stp_error("couldn't read syscall return value for pid %d: %d",
tsk->pid, rc);
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
}
// We need the first syscall argument to see what address we
@@ -843,7 +942,7 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi
if ((rc = __stp_get_user(arg0, arg0_addr)) != 0) {
_stp_error("couldn't read syscall arg 0 for pid %d: %d",
tsk->pid, rc);
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
}
#ifdef DEBUG_TASK_FINDER_VMA
@@ -851,9 +950,10 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi
"tsk %d found %s(0x%lx), returned 0x%lx\n",
tsk->pid,
((syscall_no == MMAP_SYSCALL_NO(tsk)) ? "mmap"
- : ((syscall_no == MPROTECT_SYSCALL_NO(tsk)) ? "mprotect"
- : ((syscall_no == MUNMAP_SYSCALL_NO(tsk)) ? "munmap"
- : "UNKNOWN"))),
+ : ((syscall_no == MMAP2_SYSCALL_NO(tsk)) ? "mmap2"
+ : ((syscall_no == MPROTECT_SYSCALL_NO(tsk)) ? "mprotect"
+ : ((syscall_no == MUNMAP_SYSCALL_NO(tsk)) ? "munmap"
+ : "UNKNOWN")))),
arg0, rv);
#endif
@@ -896,7 +996,7 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi
// FIXME: We'll need to figure out to
// retrieve the path of a deleted
// vma.
- rc = tgt->vm_callback(tsk, 0, NULL,
+ rc = tgt->vm_callback(tgt, tsk, 0, NULL,
entry->vm_start,
entry->vm_end,
(entry->vm_pgoff
@@ -930,7 +1030,7 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi
// FIXME: We'll need to figure out to
// retrieve the path of a deleted
// vma.
- rc = tgt->vm_callback(tsk, 0, NULL,
+ rc = tgt->vm_callback(tgt, tsk, 0, NULL,
entry->vm_start,
entry->vm_end,
(entry->vm_pgoff
@@ -963,7 +1063,7 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi
// Cleanup by deleting the saved vma info.
__stp_tf_remove_vma_entry(entry);
}
- return UTRACE_ACTION_RESUME;
+ return UTRACE_RESUME;
}
struct utrace_engine_ops __stp_utrace_task_finder_ops = {
@@ -1064,9 +1164,8 @@ stap_start_task_finder(void)
// the thread is a thread group
// leader, it is a process.
if (cb_tgt->callback != NULL) {
- rc = cb_tgt->callback(tsk, 1,
- (tsk->pid == tsk->tgid),
- cb_tgt);
+ rc = cb_tgt->callback(cb_tgt, tsk, 1,
+ (tsk->pid == tsk->tgid));
if (rc != 0) {
_stp_error("attach callback for %d failed: %d",
(int)tsk->pid, rc);
diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h
new file mode 100644
index 00000000..80037015
--- /dev/null
+++ b/runtime/utrace_compatibility.h
@@ -0,0 +1,57 @@
+/*
+ * utrace compatibility defines and inlines
+ * Copyright (C) 2008 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
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _UTRACE_COMPATIBILITY_H_
+#define _UTRACE_COMPATIBILITY_H_
+
+#include <linux/utrace.h>
+
+#ifdef UTRACE_ACTION_RESUME
+
+/*
+ * If UTRACE_ACTION_RESUME is defined after including utrace.h, we've
+ * got the original version of utrace. So that utrace clients can be
+ * written using the new interface (mostly), provide a (very thin)
+ * compatibility layer that hides the differences.
+ */
+
+#define UTRACE_ORIG_VERSION
+
+#define UTRACE_RESUME UTRACE_ACTION_RESUME
+#define UTRACE_DETACH UTRACE_ACTION_DETACH
+#define UTRACE_STOP UTRACE_ACTION_QUIESCE
+
+static inline struct utrace_attached_engine *
+utrace_attach_task(struct task_struct *target, int flags,
+ const struct utrace_engine_ops *ops, void *data)
+{
+ return utrace_attach(target, flags, ops, data);
+}
+
+static inline int __must_check
+utrace_control(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ unsigned long action)
+{
+ if (action == UTRACE_DETACH)
+ return utrace_detach(target, engine);
+ return -EINVAL;
+}
+
+static inline int __must_check
+utrace_set_events(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ unsigned long eventmask)
+{
+ return utrace_set_flags(target, engine, eventmask);
+}
+#endif
+
+#endif /* _UTRACE_COMPATIBILITY_H_ */
diff --git a/stap-client b/stap-client
index bced5e5f..3fa397a7 100755
--- a/stap-client
+++ b/stap-client
@@ -19,6 +19,7 @@
# Catch ctrl-c and other termination signals
trap 'terminate' SIGTERM
trap 'interrupt' SIGINT
+trap 'ignore_signal' SIGHUP SIGPIPE
#-----------------------------------------------------------------------------
# Helper functions.
@@ -41,6 +42,7 @@ function initialization {
p_phase=5
v_level=0
keep_temps=0
+ b_specified=0
# Create a temporary directory to package things in
# Do this before parsing the command line so that there is a place
@@ -110,6 +112,9 @@ function parse_options {
# We are at the start of an option. Look at the first character.
case $first_char in
+ b)
+ b_specified=1
+ ;;
c)
get_arg $first_token "$2"
process_c "$stap_arg"
@@ -135,7 +140,7 @@ function parse_options {
;;
m)
get_arg $first_token $2
- cmdline2="${cmdline2}m $stap_arg"
+ process_m $stap_arg
;;
o)
get_arg $first_token $2
@@ -147,7 +152,7 @@ function parse_options {
;;
r)
get_arg $first_token $2
- cmdline2="${cmdline2}r $stap_arg"
+ cmdline2="${cmdline2}r '$stap_arg'"
;;
R)
get_arg $first_token $2
@@ -155,14 +160,14 @@ function parse_options {
;;
s)
get_arg $first_token $2
- cmdline2="${cmdline2}s $stap_arg"
+ cmdline2="${cmdline2}s '$stap_arg'"
;;
v)
v_level=$(($v_level + 1))
;;
x)
get_arg $first_token $2
- cmdline2="${cmdline2}x $stap_arg"
+ cmdline2="${cmdline2}x '$stap_arg'"
;;
*)
# An unknown or unimportant flag. Ignore it, but pass it on to the server.
@@ -258,11 +263,19 @@ function process_I {
cmdline2="${cmdline2}I 'tapsets/$local_name'"
}
+# function: process_m ARGUMENT
+#
+# Process the -m flag.
+function process_m {
+ m_name="$1"
+ cmdline2="${cmdline2}m '$1'"
+}
+
# function: process_o ARGUMENT
#
# Process the -o flag.
function process_o {
- stdout_redirection="> $1"
+ stdout_redirection="$1"
cmdline2="${cmdline2}o '$1'"
}
@@ -531,13 +544,30 @@ function disconnect_from_server {
#
# Write the stdout and stderr from the server to stdout and stderr respectively.
function process_response {
+ # Pick up the results of running stap on the server.
+ rc=`cat rc`
+
+ # Copy the module to the current directory, if -m was specified
+ if test "X$m_name" != "X"; then
+ if test -f $tmpdir_stap/$m_name.ko; then
+ cp $tmpdir_stap/$m_name.ko $wd
+ else
+ stream_output
+ fatal "module $tmpdir_stap/$m_name.ko does not exist"
+ fi
+ fi
+
# Output stdout and stderr as directed
+ stream_output
+}
+
+# function: stream_output
+#
+# Output stdout and stderr as directed
+function stream_output {
cd $tmpdir_server
cat stderr >&2
- eval cat stdout $stdout_redirection
-
- # Pick up the results of running stap on the server.
- rc=`cat rc`
+ cat stdout
}
# function: maybe_call_staprun
@@ -566,6 +596,8 @@ function maybe_call_staprun {
fi
if test $p_phase = 5; then
+ test $v_level -gt 0 && echo "Pass 5: starting run." >&2
+
# We have a module. Try to run it
# If a -c command was specified, pass it along.
if test "X$c_cmd" != "X"; then
@@ -574,21 +606,37 @@ function maybe_call_staprun {
# The -v level will be one less than what was specified
# for us.
- for ((--v_level; $v_level > 0; --v_level))
+ for ((vl=$((v_level - 1)); $vl > 0; --vl))
do
staprun_opts="$staprun_opts -v"
done
+ # if -o was specified, pass it along
+ if test "X$stdout_redirection" != "X"; then
+ staprun_opts="$staprun_opts -o $stdout_redirection"
+ fi
+
# Run it in the background and wait for it. This
# way any signals send to us can be caught.
+ if test $v_level -ge 2; then
+ echo "running `which staprun` $staprun_opts $tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'`" >&2
+ fi
PATH=`staprun_PATH` eval staprun "$staprun_opts" \
- $tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'` &
+ $tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'`
staprun_running=1
- wait %?staprun
+ wait '%?staprun' > /dev/null 2>&1
rc=$?
staprun_running=0
# 127 from wait means that the job was already finished.
test $rc=127 && rc=0
+
+ # Wait until the job actually disappears so that its output is complete.
+ while jobs '%?staprun' >/dev/null 2>&1
+ do
+ sleep 1
+ done
+
+ test $v_level -gt 0 && echo "Pass 5: run completed in 0usr/0sys/0real ms." >&2
fi
fi
}
@@ -640,11 +688,11 @@ function cleanup {
# Terminate gracefully.
function terminate {
# Clean up
- echo "$0: terminated by signal"
+ echo "$0: terminated by signal" >&2
cleanup
# Kill any running staprun job
- kill -s SIGTERM %?staprun 2>/dev/null
+ kill -s SIGTERM '%?staprun' 2>/dev/null
exit 1
}
@@ -654,11 +702,21 @@ function terminate {
# Pass an interrupt (ctrl-C) to staprun
function interrupt {
# Pass the signal on to any running staprun job
- kill -s SIGINT %?staprun 2>/dev/null
+ if test $staprun_running = 1; then
+ kill -s SIGINT '%?staprun' 2>/dev/null
+ return
+ fi
+
+ # If staprun was not running, then exit.
+ cleanup
+ exit 1
+}
- # If staprun was running, then just interrupt it. Otherwise
- # we exit.
- test $staprun_running = 0 && exit 1
+# function: ignore_signal
+#
+# Called in order to ignore a signal
+function ignore_signal {
+ :
}
#-----------------------------------------------------------------------------
diff --git a/stap-server b/stap-server
index 12f93757..b82bc695 100755
--- a/stap-server
+++ b/stap-server
@@ -69,7 +69,7 @@ function receive_request {
nc -l $port < /dev/zero > $tar_client &
# Wait for the transfer to complete.
- wait %nc
+ wait '%nc' >/dev/null 2>&1
}
# function: unpack_request
@@ -159,25 +159,18 @@ function read_data_file {
# Verify the first line of the file.
read <&3
- line=$REPLY
+ line="$REPLY"
data=`expr "$line" : "$1: \\\(.*\\\)"`
if test "X$data" = "X"; then
fatal "ERROR: Data in file $1 is incorrect"
return
fi
- # Add any additional lines of data
- while read <&3
- do
- data="$data
-$REPLY"
- done
-
# Close the file
exec 3<&-
- # Echo the result
- echo "$data"
+ # Now read the entire file.
+ cat $1 | sed "s/$1: //"
}
# function: parse_options [ STAP-OPTIONS ]
@@ -397,7 +390,7 @@ function send_response {
# in order to workaround a nc bug. It closes the connection
# early if stdin from the other side is not provided.
nc -l $port < $tar_server > /dev/null &
- wait %nc
+ wait '%nc' >/dev/null 2>&1
}
# function: fatal [ MESSAGE ]
diff --git a/stap-serverd b/stap-serverd
index a6611255..6970217d 100755
--- a/stap-serverd
+++ b/stap-serverd
@@ -78,7 +78,7 @@ function listen {
advertise_presence
first=0
fi
- wait %nc
+ wait '%nc' >/dev/null 2>&1
rc=$?
if test $rc = 127 -o $rc = 0; then
break; # success
@@ -110,11 +110,11 @@ function terminate {
# Kill the running 'avahi-publish-service' job
kill -s SIGTERM %avahi-publish-service 2> /dev/null
- wait %avahi-publish-service 2> /dev/null
+ wait '%avahi-publish-service' >/dev/null 2>&1
# Kill any running 'nc -l' job.
kill -s SIGTERM "%nc -l" 2> /dev/null
- wait "%nc - l" 2> /dev/null
+ wait "%nc - l" >/dev/null 2>&1
# Clean up
cd `dirname $tmpdir`
diff --git a/tapsets.cxx b/tapsets.cxx
index 8f0b38b4..3d4d0dc9 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -5702,7 +5702,7 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
// Output task finder callback routine that gets called for all
// itrace probe types.
- s.op->newline() << "static int _stp_itrace_probe_cb(struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {";
+ s.op->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
s.op->indent(1);
s.op->newline() << "int rc = 0;";
s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
@@ -6084,12 +6084,12 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
case UDPF_BEGIN: // process begin
s.op->line() << " .flags=(UDPF_BEGIN),";
s.op->line() << " .ops={ .report_quiesce=stap_utrace_probe_quiesce },";
- s.op->line() << " .events=(UTRACE_ACTION_QUIESCE|UTRACE_EVENT(QUIESCE)),";
+ s.op->line() << " .events=(UTRACE_STOP|UTRACE_EVENT(QUIESCE)),";
break;
case UDPF_THREAD_BEGIN: // thread begin
s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
s.op->line() << " .ops={ .report_quiesce=stap_utrace_probe_quiesce },";
- s.op->line() << " .events=(UTRACE_ACTION_QUIESCE|UTRACE_EVENT(QUIESCE)),";
+ s.op->line() << " .events=(UTRACE_STOP|UTRACE_EVENT(QUIESCE)),";
break;
// Notice we're not setting up a .ops/.report_death handler for
@@ -6104,17 +6104,19 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
// For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death
// handler isn't strictly necessary. However, it helps to keep
- // our attaches/detaches symmetrical.
+ // our attaches/detaches symmetrical. Notice we're using quiesce
+ // as a workaround for bug 6841.
case UDPF_SYSCALL:
s.op->line() << " .flags=(UDPF_SYSCALL),";
- s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
+ s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death, .report_quiesce=stap_utrace_probe_syscall_quiesce },";
+ s.op->line() << " .events=(UTRACE_STOP|UTRACE_EVENT(QUIESCE)|UTRACE_EVENT(DEATH)),";
break;
case UDPF_SYSCALL_RETURN:
s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
- s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
+ s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death, .report_quiesce=stap_utrace_probe_syscall_quiesce },";
+ s.op->line() << " .events=(UTRACE_STOP|UTRACE_EVENT(QUIESCE)|UTRACE_EVENT(DEATH)),";
break;
+
case UDPF_NONE:
s.op->line() << " .flags=(UDPF_NONE),";
s.op->line() << " .ops={ },";
@@ -6200,7 +6202,11 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
// Output handler function for UDPF_BEGIN and UDPF_THREAD_BEGIN
if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
{
+ s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
s.op->newline() << "static u32 stap_utrace_probe_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) {";
+ s.op->newline() << "#else";
+ s.op->newline() << "static u32 stap_utrace_probe_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event) {";
+ s.op->newline() << "#endif";
s.op->indent(1);
s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
@@ -6211,10 +6217,9 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "(*p->ph) (c);";
common_probe_entryfn_epilogue (s.op);
- // UTRACE_ACTION_NEWSTATE not needed here to clear quiesce since
- // we're detaching - utrace automatically restarts the thread.
+ // we're detaching, so utrace automatically restarts the thread.
s.op->newline() << "debug_task_finder_detach();";
- s.op->newline() << "return UTRACE_ACTION_DETACH;";
+ s.op->newline() << "return UTRACE_DETACH;";
s.op->newline(-1) << "}";
}
@@ -6238,7 +6243,39 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
// Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events
if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
+ s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
+ s.op->newline() << "static u32 stap_utrace_probe_syscall_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) {";
+ s.op->newline() << "#else";
+ s.op->newline() << "static u32 stap_utrace_probe_syscall_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event) {";
+ s.op->newline() << "#endif";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
+ s.op->newline() << "int rc = 0;";
+
+ // Turn off quiesce handling and turn on either syscall entry
+ // or exit events.
+ s.op->newline() << "if (p->flags == UDPF_SYSCALL)";
+ s.op->indent(1);
+ s.op->newline() << "rc = utrace_set_events(tsk, engine, UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH));";
+ s.op->indent(-1);
+ s.op->newline() << "else if (p->flags == UDPF_SYSCALL_RETURN)";
+ s.op->indent(1);
+ s.op->newline() << "rc = utrace_set_events(tsk, engine, UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH));";
+ s.op->indent(-1);
+ s.op->newline() << "if (rc != 0)";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"utrace_set_events returned error %d on pid %d\", rc, (int)tsk->pid);";
+ s.op->indent(-1);
+
+ s.op->newline() << "return UTRACE_RESUME;";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
+ s.op->newline() << "#else";
+ s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
+ s.op->newline() << "#endif";
+
s.op->indent(1);
s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
@@ -6250,13 +6287,13 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "(*p->ph) (c);";
common_probe_entryfn_epilogue (s.op);
- s.op->newline() << "return UTRACE_ACTION_RESUME;";
+ s.op->newline() << "return UTRACE_RESUME;";
s.op->newline(-1) << "}";
}
// Output task_finder callback routine that gets called for all
// utrace probe types.
- s.op->newline() << "static int _stp_utrace_probe_cb(struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {";
+ s.op->newline() << "static int _stp_utrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
s.op->indent(1);
s.op->newline() << "int rc = 0;";
s.op->newline() << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);";
@@ -9143,21 +9180,24 @@ register_standard_tapsets(systemtap_session & s)
->bind(new utrace_builder ());
s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
->bind(new utrace_builder ());
-
- // itrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind("itrace")
- ->bind(new itrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("itrace")
- ->bind(new itrace_builder ());
-
s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)
->bind(new utrace_builder ());
s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)
->bind(new utrace_builder ());
+ s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)
+ ->bind(new utrace_builder ());
s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
->bind(new utrace_builder ());
s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
->bind(new utrace_builder ());
+ s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
+ ->bind(new utrace_builder ());
+
+ // itrace user-space probes
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("itrace")
+ ->bind(new itrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("itrace")
+ ->bind(new itrace_builder ());
// marker-based parts
s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)