summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--runtime/ChangeLog14
-rw-r--r--runtime/task_finder.c92
-rw-r--r--tapsets.cxx293
-rw-r--r--testsuite/ChangeLog5
-rw-r--r--testsuite/systemtap.base/utrace_p4.exp27
-rw-r--r--testsuite/systemtap.base/utrace_p5.exp50
7 files changed, 306 insertions, 191 deletions
diff --git a/ChangeLog b/ChangeLog
index aa727664..c480d814 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-06-06 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (enum utrace_derived_probe_flags): Redefined in
+ terms of probe types instead of utrace events.
+ (utrace_var_expanding_copy_visitor::visit_target_symbol): Uses new
+ utrace_derived_probes_flags values.
+ (utrace_builder::build): Handles new probe types and new
+ utrace_derived_probes_flags values.
+ (utrace_derived_probe_group::emit_probe_decl): Updated to handle
+ new utrace_derived_probe_flags values.
+ (utrace_derived_probe_group::emit_module_decls): Ditto. Also
+ correctly handles 'begin' events correctly by installing a quiesce
+ handler (instead of running the probe directly).
+ (register_standard_tapsets): Registers updated utrace probe
+ types.
+
2008-06-05 Srinivasa DS <srinivasa@in.ibm.com>
*configure,configure.ac: -fpie option puts limit on GOT size
and hence systemtap build fails on s390. So use -fPIE which
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index c9cd07fc..8ef5550f 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,17 @@
+2008-06-06 David Smith <dsmith@redhat.com>
+
+ * task_finder.c: Added some debug logic. Use
+ '-DDEBUG_TASK_FINDER' to enable.
+ (stap_utrace_attach): Renamed from '__stp_utrace_attach'.
+ (__stp_utrace_attach_match_filename): Calls callback with
+ notification that this is a process or thread event.
+ (__stp_utrace_attach_match_tsk): Ditto.
+ (__stp_utrace_task_finder_report_clone): Ditto.
+ (__stp_utrace_task_finder_report_exec): Ditto.
+ (stap_utrace_task_finder_report_death): Ditto.
+ (stap_start_task_finder): Ditto.
+ (stap_stop_task_finder): Added debug logic.
+
2008-05-29 Stan Cox <scox@redhat.com>
* map.c (print_keytype): Remove.
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 9b03234d..e233d463 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -11,9 +11,22 @@ struct stap_task_finder_target;
#define __STP_TF_STOPPED 3
atomic_t __stp_task_finder_state = ATOMIC_INIT(__STP_TF_STARTING);
+#ifdef DEBUG_TASK_FINDER
+atomic_t __stp_attach_count = ATOMIC_INIT (0);
+
+#define debug_task_finder_attach() (atomic_inc(&__stp_attach_count))
+#define debug_task_finder_detach() (atomic_dec(&__stp_attach_count))
+#define debug_task_finder_report() (_stp_dbug(__FUNCTION__, __LINE__, \
+ "attach count: %d\n", atomic_read(&__stp_attach_count)))
+#else
+#define debug_task_finder_attach() /* empty */
+#define debug_task_finder_detach() /* empty */
+#define debug_task_finder_report() /* empty */
+#endif
+
typedef int (*stap_task_finder_callback)(struct task_struct *tsk,
int register_p,
- unsigned long event_flag,
+ int process_p,
struct stap_task_finder_target *tgt);
struct stap_task_finder_target {
@@ -116,6 +129,7 @@ stap_utrace_detach_ops(struct utrace_engine_ops *ops)
}
else if (engine != NULL) {
utrace_detach(tsk, engine);
+ debug_task_finder_detach();
}
}
} while_each_thread(grp, tsk);
@@ -126,6 +140,7 @@ udo_err:
_stp_error("utrace_attach returned error %d on pid %d",
error, pid);
}
+ debug_task_finder_report();
}
static void
@@ -198,9 +213,9 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
#define __STP_UTRACE_ATTACHED_TASK_EVENTS (UTRACE_EVENT(DEATH))
static int
-__stp_utrace_attach(struct task_struct *tsk,
- const struct utrace_engine_ops *ops, void *data,
- unsigned long event_flags)
+stap_utrace_attach(struct task_struct *tsk,
+ const struct utrace_engine_ops *ops, void *data,
+ unsigned long event_flags)
{
struct utrace_attached_engine *engine;
struct mm_struct *mm;
@@ -232,6 +247,7 @@ __stp_utrace_attach(struct task_struct *tsk,
}
else {
utrace_set_flags(tsk, engine, event_flags);
+ debug_task_finder_attach();
}
return rc;
}
@@ -239,8 +255,7 @@ __stp_utrace_attach(struct task_struct *tsk,
static inline void
__stp_utrace_attach_match_filename(struct task_struct *tsk,
const char * const filename,
- int register_p,
- unsigned long event_flag)
+ int register_p, int process_p)
{
size_t filelen;
struct list_head *tgt_node;
@@ -274,7 +289,7 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
if (cb_tgt->callback != NULL) {
int rc = cb_tgt->callback(tsk, register_p,
- event_flag, cb_tgt);
+ process_p, cb_tgt);
if (rc != 0) {
_stp_error("callback for %d failed: %d",
(int)tsk->pid, rc);
@@ -284,9 +299,9 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
// Set up thread death notification.
if (register_p) {
- rc = __stp_utrace_attach(tsk, &cb_tgt->ops,
- cb_tgt,
- __STP_UTRACE_ATTACHED_TASK_EVENTS);
+ rc = stap_utrace_attach(tsk, &cb_tgt->ops,
+ cb_tgt,
+ __STP_UTRACE_ATTACHED_TASK_EVENTS);
if (rc != 0 && rc != EPERM)
break;
cb_tgt->engine_attached = 1;
@@ -298,6 +313,7 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
&cb_tgt->ops, 0);
if (! IS_ERR(engine) && engine != NULL) {
utrace_detach(tsk, engine);
+ debug_task_finder_detach();
}
}
}
@@ -316,7 +332,7 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk,
static void
__stp_utrace_attach_match_tsk(struct task_struct *path_tsk,
struct task_struct *match_tsk, int register_p,
- unsigned long event_flag)
+ int process_p)
{
struct mm_struct *mm;
char *mmpath_buf;
@@ -351,7 +367,7 @@ __stp_utrace_attach_match_tsk(struct task_struct *path_tsk,
}
else {
__stp_utrace_attach_match_filename(match_tsk, mmpath,
- register_p, event_flag);
+ register_p, process_p);
}
_stp_kfree(mmpath_buf);
@@ -373,12 +389,13 @@ __stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine,
return UTRACE_ACTION_RESUME;
// On clone, attach to the child.
- rc = __stp_utrace_attach(child, engine->ops, 0,
- __STP_UTRACE_TASK_FINDER_EVENTS);
+ rc = stap_utrace_attach(child, engine->ops, 0,
+ __STP_UTRACE_TASK_FINDER_EVENTS);
if (rc != 0 && rc != EPERM)
return UTRACE_ACTION_RESUME;
- __stp_utrace_attach_match_tsk(parent, child, 1, UTRACE_EVENT(CLONE));
+ __stp_utrace_attach_match_tsk(parent, child, 1,
+ (clone_flags & CLONE_THREAD) == 0);
return UTRACE_ACTION_RESUME;
}
@@ -402,16 +419,17 @@ __stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine,
// was probing '/bin/bash', the cloned thread is still
// '/bin/bash' up until the exec.
if (tsk != NULL && tsk->parent != NULL && tsk->parent->pid > 1) {
- __stp_utrace_attach_match_tsk(tsk->parent, tsk, 0,
- UTRACE_EVENT(EXEC));
+ // We'll hardcode this as a process end, but a thread
+ // *could* call exec (although they aren't supposed to).
+ __stp_utrace_attach_match_tsk(tsk->parent, tsk, 0, 1);
}
// On exec, check bprm
if (bprm->filename == NULL)
return UTRACE_ACTION_RESUME;
- __stp_utrace_attach_match_filename(tsk, bprm->filename, 1,
- UTRACE_EVENT(EXEC));
+ // We assume that all exec's are exec'ing a new process
+ __stp_utrace_attach_match_filename(tsk, bprm->filename, 1, 1);
return UTRACE_ACTION_RESUME;
}
@@ -420,6 +438,7 @@ static u32
stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine,
struct task_struct *tsk)
{
+ debug_task_finder_detach();
return UTRACE_ACTION_DETACH;
}
@@ -430,6 +449,7 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
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;
}
@@ -446,12 +466,15 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
int rc;
// Call the callback
- rc = tgt->callback(tsk, 0, UTRACE_EVENT(DEATH), tgt);
+ rc = tgt->callback(tsk, 0,
+ (atomic_read(&tsk->signal->live) == 0),
+ tgt);
if (rc != 0) {
_stp_error("death callback for %d failed: %d",
(int)tsk->pid, rc);
}
}
+ debug_task_finder_detach();
return UTRACE_ACTION_DETACH;
}
@@ -483,8 +506,8 @@ stap_start_task_finder(void)
size_t mmpathlen;
struct list_head *tgt_node;
- rc = __stp_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
- __STP_UTRACE_TASK_FINDER_EVENTS);
+ rc = stap_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
+ __STP_UTRACE_TASK_FINDER_EVENTS);
if (rc == EPERM) {
/* Ignore EPERM errors, which mean this wasn't
* a thread we can attach to. */
@@ -539,17 +562,12 @@ stap_start_task_finder(void)
if (cb_tgt == NULL || cb_tgt->callback == NULL)
continue;
- // Call the callback. Notice we're
- // not passing a valid event_flag
- // here. That's OK, for 2 reasons.
- // (1) We're not in the
- // STAP_SESSION_RUNNING state yet, so
- // probes won't get called anyway.
- // (2) There really isn't an event
- // associated with this callback call,
- // we just want to let the caller
- // attach to the thread.
- rc = cb_tgt->callback(tsk, 1, 0, cb_tgt);
+ // Call the callback. Assume that if
+ // the thread is a thread group
+ // leader, it is a process.
+ rc = cb_tgt->callback(tsk, 1,
+ (tsk->pid == tsk->tgid),
+ cb_tgt);
if (rc != 0) {
_stp_error("attach callback for %d failed: %d",
(int)tsk->pid, rc);
@@ -557,9 +575,9 @@ stap_start_task_finder(void)
}
// Set up thread death notification.
- rc = __stp_utrace_attach(tsk, &cb_tgt->ops,
- cb_tgt,
- __STP_UTRACE_ATTACHED_TASK_EVENTS);
+ rc = stap_utrace_attach(tsk, &cb_tgt->ops,
+ cb_tgt,
+ __STP_UTRACE_ATTACHED_TASK_EVENTS);
if (rc != 0 && rc != EPERM)
goto stf_err;
cb_tgt->engine_attached = 1;
@@ -577,7 +595,9 @@ static void
stap_stop_task_finder(void)
{
atomic_set(&__stp_task_finder_state, __STP_TF_STOPPING);
+ debug_task_finder_report();
stap_utrace_detach_ops(&__stp_utrace_task_finder_ops);
__stp_task_finder_cleanup();
+ debug_task_finder_report();
atomic_set(&__stp_task_finder_state, __STP_TF_STOPPED);
}
diff --git a/tapsets.cxx b/tapsets.cxx
index 85d381a3..ef701564 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -5100,27 +5100,19 @@ task_finder_derived_probe_group::emit_module_exit (systemtap_session& s)
// utrace user-space probes
// ------------------------------------------------------------------------
+static string TOK_THREAD("thread");
static string TOK_SYSCALL("syscall");
-// Since we don't have access to <linux/utrace.h>, we'll have to
-// define our own version of the UTRACE_EVENT flags.
+// Note that these flags don't match up exactly with UTRACE_EVENT
+// flags (and that's OK).
enum utrace_derived_probe_flags {
UDPF_NONE,
- UDPF_QUIESCE, // UTRACE_EVENT(QUIESCE)
- UDPF_REAP, // UTRACE_EVENT(REAP)
- UDPF_CLONE, // UTRACE_EVENT(CLONE)
- UDPF_VFORK_DONE, // UTRACE_EVENT(VFORK_DONE)
- UDPF_EXEC, // UTRACE_EVENT(EXEC)
- UDPF_EXIT, // UTRACE_EVENT(EXIT)
- UDPF_DEATH, // UTRACE_EVENT(DEATH)
- UDPF_SYSCALL_ENTRY, // UTRACE_EVENT(SYSCALL_ENTRY)
- UDPF_SYSCALL_EXIT, // UTRACE_EVENT(SYSCALL_EXIT)
- UDPF_SIGNAL, // UTRACE_EVENT(SIGNAL)
- UDPF_SIGNAL_IGN, // UTRACE_EVENT(SIGNAL_IGN)
- UDPF_SIGNAL_STOP, // UTRACE_EVENT(SIGNAL_STOP)
- UDPF_SIGNAL_TERM, // UTRACE_EVENT(SIGNAL_TERM)
- UDPF_SIGNAL_CORE, // UTRACE_EVENT(SIGNAL_CORE)
- UDPF_JCTL, // UTRACE_EVENT(JCTL)
+ UDPF_BEGIN, // process begin
+ UDPF_END, // process end
+ UDPF_THREAD_BEGIN, // thread begin
+ UDPF_THREAD_END, // thread end
+ UDPF_SYSCALL, // syscall entry
+ UDPF_SYSCALL_RETURN, // syscall exit
UDPF_NFLAGS
};
@@ -5214,7 +5206,7 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
{
assert(e->base_name.size() > 0 && e->base_name[0] == '$');
- if (flags != UDPF_SYSCALL_ENTRY && flags != UDPF_SYSCALL_EXIT)
+ if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols",
e->tok);
@@ -5293,19 +5285,24 @@ struct utrace_builder: public derived_probe_builder
enum utrace_derived_probe_flags flags = UDPF_NONE;
assert (has_path || has_pid);
- if (has_null_param (parameters, "death"))
- flags = UDPF_DEATH;
+ if (has_null_param (parameters, TOK_THREAD))
+ {
+ if (has_null_param (parameters, TOK_BEGIN))
+ flags = UDPF_THREAD_BEGIN;
+ else if (has_null_param (parameters, TOK_END))
+ flags = UDPF_THREAD_END;
+ }
else if (has_null_param (parameters, TOK_SYSCALL))
{
if (has_null_param (parameters, TOK_RETURN))
- flags = UDPF_SYSCALL_EXIT;
+ flags = UDPF_SYSCALL_RETURN;
else
- flags = UDPF_SYSCALL_ENTRY;
+ flags = UDPF_SYSCALL;
}
- else if (has_null_param (parameters, "clone"))
- flags = UDPF_CLONE;
- else if (has_null_param (parameters, "exec"))
- flags = UDPF_EXEC;
+ else if (has_null_param (parameters, TOK_BEGIN))
+ flags = UDPF_BEGIN;
+ else if (has_null_param (parameters, TOK_END))
+ flags = UDPF_END;
// If we have a path, we need to validate it.
if (has_path)
@@ -5390,31 +5387,41 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
// Handle flags
switch (p->flags)
{
- case UDPF_CLONE:
- // Notice we're not setting up a .ops/.report_clone handler here.
- // Instead, we'll just call the probe directly when we get
- // notified the clone happened.
- s.op->line() << " .flags=(UTRACE_EVENT(CLONE)),";
+ // Look in _stp_utrace_probe_cb for description of why quiesce is
+ // used here.
+ 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)),";
break;
- case UDPF_EXEC:
- // Notice we're not setting up a .ops/.report_exec handler here.
- // Instead, we'll just call the probe directly when we get
- // notified the exec happened.
- s.op->line() << " .flags=(UTRACE_EVENT(EXEC)),";
+ 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)),";
break;
- case UDPF_DEATH:
- // Notice we're not setting up a .ops/.report_death handler
- // here. Instead, we'll just call the probe directly when we
- // get notified the death happened.
- s.op->line() << " .flags=(UTRACE_EVENT(DEATH)),";
+
+ // Notice we're not setting up a .ops/.report_death handler for
+ // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call
+ // the probe directly when we get notified.
+ case UDPF_END: // process end
+ s.op->line() << " .flags=(UDPF_END),";
break;
- case UDPF_SYSCALL_ENTRY:
+ case UDPF_THREAD_END: // thread end
+ s.op->line() << " .flags=(UDPF_THREAD_END),";
+ break;
+
+ // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death
+ // handler isn't strictly necessary. However, it helps to keep
+ // our attaches/detaches symmetrical.
+ 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() << " .flags=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
+ s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
break;
- case UDPF_SYSCALL_EXIT:
+ 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() << " .flags=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
+ s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
break;
default:
throw semantic_error ("bad utrace probe flag");
@@ -5433,19 +5440,53 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline();
s.op->newline() << "/* ---- utrace probes ---- */";
+ s.op->newline() << "enum utrace_derived_probe_flags {";
+ s.op->indent(1);
+ s.op->newline() << "UDPF_NONE,";
+ s.op->newline() << "UDPF_BEGIN,";
+ s.op->newline() << "UDPF_END,";
+ s.op->newline() << "UDPF_THREAD_BEGIN,";
+ s.op->newline() << "UDPF_THREAD_END,";
+ s.op->newline() << "UDPF_SYSCALL,";
+ s.op->newline() << "UDPF_SYSCALL_RETURN,";
+ s.op->newline() << "UDPF_NFLAGS";
+ s.op->newline(-1) << "};";
+
s.op->newline() << "struct stap_utrace_probe {";
s.op->indent(1);
s.op->newline() << "struct stap_task_finder_target tgt;";
s.op->newline() << "const char *pp;";
s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "enum utrace_derived_probe_flags flags;";
s.op->newline() << "struct utrace_engine_ops ops;";
- s.op->newline() << "unsigned long flags;";
+ s.op->newline() << "unsigned long events;";
s.op->newline() << "int engine_attached;";
s.op->newline(-1) << "};";
- // Output handler function for CLONE, EXEC, and DEATH events
- if (flags_seen[UDPF_CLONE] || flags_seen[UDPF_EXEC]
- || flags_seen[UDPF_DEATH])
+
+ // Output handler function for UDPF_BEGIN and UDPF_THREAD_BEGIN
+ if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
+ {
+ s.op->newline() << "static u32 stap_utrace_probe_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING");
+ s.op->newline() << "c->probe_point = p->pp;";
+
+ // call probe function
+ 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.
+ s.op->newline() << "debug_task_finder_detach();";
+ s.op->newline() << "return UTRACE_ACTION_DETACH;";
+ s.op->newline(-1) << "}";
+ }
+
+ // Output handler function for UDPF_END and UDPF_THREAD_END
+ if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
{
s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
s.op->indent(1);
@@ -5462,7 +5503,7 @@ 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_ENTRY] || flags_seen[UDPF_SYSCALL_EXIT])
+ if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
s.op->indent(1);
@@ -5480,9 +5521,9 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(-1) << "}";
}
- // Output task finder callback routine that gets called for all
+ // 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, unsigned long event_flag, struct stap_task_finder_target *tgt) {";
+ 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->indent(1);
s.op->newline() << "int rc = 0;";
s.op->newline() << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);";
@@ -5493,108 +5534,134 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "switch (p->flags) {";
s.op->indent(1);
- // When registering an clone/exec probe, we can't install a utrace
- // engine, since we're already in the clone/exec event. So, we just
- // call the probe directly. Note that for existing threads, this
- // won't really work since our state isn't STAP_SESSION_RUNNING yet.
- // But that's OK, since this isn't really a 'clone/exec' event - it
- // is a notification that task_finder found an interesting process.
- if (flags_seen[UDPF_CLONE])
- {
- s.op->newline() << "case UTRACE_EVENT(CLONE):";
+
+ // When receiving a UTRACE_EVENT(CLONE) event, we can't call the
+ // begin/thread.begin probe directly. So, we'll just attach an
+ // engine that waits for the thread to quiesce. When the thread
+ // quiesces, then call the probe.
+ if (flags_seen[UDPF_BEGIN])
+ {
+ s.op->newline() << "case UDPF_BEGIN:";
s.op->indent(1);
- s.op->newline() << "if (event_flag == UTRACE_EVENT(CLONE)) {";
+ s.op->newline() << "if (process_p) {";
s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
+ s.op->indent(1);
+ s.op->newline() << "p->engine_attached = 1;";
+ s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
- }
- if (flags_seen[UDPF_EXEC])
- {
- s.op->newline() << "case UTRACE_EVENT(EXEC):";
+ }
+ if (flags_seen[UDPF_THREAD_BEGIN])
+ {
+ s.op->newline() << "case UDPF_THREAD_BEGIN:";
s.op->indent(1);
- s.op->newline() << "if (event_flag == UTRACE_EVENT(EXEC)) {";
+ s.op->newline() << "if (! process_p) {";
s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
+ s.op->indent(1);
+ s.op->newline() << "p->engine_attached = 1;";
+ s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
- }
- // For death probes, do nothing at registration time. We'll handle
- // these in the 'register_p == 0' case.
- if (flags_seen[UDPF_DEATH])
+ }
+
+ // For end/thread_end probes, do nothing at registration time.
+ // We'll handle these in the 'register_p == 0' case.
+ if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
{
- s.op->newline() << "case UTRACE_EVENT(DEATH):";
+ s.op->newline() << "case UDPF_END:";
+ s.op->newline() << "case UDPF_THREAD_END:";
s.op->indent(1);
s.op->newline() << "break;";
s.op->indent(-1);
}
+
// Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events.
- if (flags_seen[UDPF_SYSCALL_ENTRY] || flags_seen[UDPF_SYSCALL_EXIT])
+ if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
- s.op->newline() << "case (UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)):";
- s.op->newline() << "case (UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)):";
- s.op->indent(1);
- s.op->newline() << "engine = utrace_attach(tsk, UTRACE_ATTACH_CREATE, &p->ops, p);";
- s.op->newline() << "if (IS_ERR(engine)) {";
- s.op->indent(1);
- s.op->newline() << "int error = -PTR_ERR(engine);";
- s.op->newline() << "if (error != ENOENT) {";
- s.op->indent(1);
- s.op->newline() << "_stp_error(\"utrace_attach returned error %d on pid %d\", error, (int)tsk->pid);";
- s.op->newline() << "rc = error;";
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
- s.op->newline() << "else if (unlikely(engine == NULL)) {";
+ s.op->newline() << "case UDPF_SYSCALL:";
+ s.op->newline() << "case UDPF_SYSCALL_RETURN:";
s.op->indent(1);
- s.op->newline() << "_stp_error(\"utrace_attach returned NULL on pid %d!\", (int)tsk->pid);";
- s.op->newline() << "rc = ENOENT;";
- s.op->newline(-1) << "}";
- s.op->newline() << "else {";
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
s.op->indent(1);
- s.op->newline() << "utrace_set_flags(tsk, engine, p->flags);";
s.op->newline() << "p->engine_attached = 1;";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
+
+ s.op->newline() << "default:";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
+
// Since this engine could be attached to multiple threads, don't
- // cleanup here. We'll cleanup at module unload time.
+ // call stap_utrace_detach_ops() here.
s.op->newline() << "else {";
s.op->indent(1);
s.op->newline() << "switch (p->flags) {";
s.op->indent(1);
// For death probes, go ahead and call the probe directly.
- if (flags_seen[UDPF_DEATH])
+ if (flags_seen[UDPF_END])
{
- s.op->newline() << "case UTRACE_EVENT(DEATH):";
+ s.op->newline() << "case UDPF_END:";
s.op->indent(1);
- s.op->newline() << "if (event_flag == UTRACE_EVENT(DEATH)) {";
+ s.op->newline() << "if (process_p) {";
s.op->indent(1);
s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
- if (flags_seen[UDPF_SYSCALL_ENTRY] || flags_seen[UDPF_SYSCALL_EXIT])
+ if (flags_seen[UDPF_THREAD_END])
{
- s.op->newline() << "case (UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)):";
- s.op->newline() << "case (UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)):";
+ s.op->newline() << "case UDPF_THREAD_END:";
s.op->indent(1);
- s.op->newline() << "if (event_flag == UTRACE_EVENT(EXEC)) {";
+ s.op->newline() << "if (! process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ // For begin/thread_begin probes, at deregistration time we'll try
+ // to detach. This will only be necessary if the new thread/process
+ // got killed before the probe got run in the UTRACE_EVENT(QUIESCE)
+ // handler.
+ if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
+ || flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
+ {
+ s.op->newline() << "case UDPF_BEGIN:";
+ s.op->newline() << "case UDPF_THREAD_BEGIN:";
+ s.op->newline() << "case UDPF_SYSCALL:";
+ s.op->newline() << "case UDPF_SYSCALL_RETURN:";
s.op->indent(1);
s.op->newline() << "engine = utrace_attach(tsk, UTRACE_ATTACH_MATCH_OPS, &p->ops, 0);";
s.op->newline() << "if (! IS_ERR(engine) && engine != NULL) {";
s.op->indent(1);
s.op->newline() << "utrace_detach(tsk, engine);";
- s.op->newline(-1) << "}";
+ s.op->newline() << "debug_task_finder_detach();";
+
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
+
+ s.op->newline() << "default:";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
s.op->newline() << "return rc;";
@@ -8093,13 +8160,21 @@ register_standard_tapsets(systemtap_session & s)
->bind(new uprobe_builder ());
// utrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind("clone")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_BEGIN)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_BEGIN)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_END)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("clone")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_END)
->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind("exec")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("exec")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
->bind(new utrace_builder ());
s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)
->bind(new utrace_builder ());
@@ -8109,10 +8184,6 @@ register_standard_tapsets(systemtap_session & s)
->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_str(TOK_PROCESS)->bind("death")
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("death")
- ->bind(new utrace_builder ());
// marker-based parts
s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index e041a934..0c414115 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-06-06 David Smith <dsmith@redhat.com>
+
+ * systemtap.base/utrace_p4.exp: Updated for utrace probe changes.
+ * systemtap.base/utrace_p5.exp: Ditto.
+
2008-06-03 Frank Ch. Eigler <fche@elastic.org>
* systemtap.context/backtrace.tcl: Tolerate "(inexact)" backtraces.
diff --git a/testsuite/systemtap.base/utrace_p4.exp b/testsuite/systemtap.base/utrace_p4.exp
index eb6ea685..5544ee55 100644
--- a/testsuite/systemtap.base/utrace_p4.exp
+++ b/testsuite/systemtap.base/utrace_p4.exp
@@ -49,11 +49,12 @@ proc stap_compile { TEST_NAME compile script args } {
# Initialize variables
set utrace_support_found 0
-set clone_script {"probe process(\"/bin/ls\").clone { print(\"ls clone\") }"}
-set death_script {"probe process(\"/bin/ls\").death { print(\"ls death\") }"}
+set begin_script {"probe process(\"/bin/ls\").begin { print(\"ls begin\") }"}
+set end_script {"probe process(\"/bin/ls\").end { print(\"ls end\") }"}
set syscall_script {"probe process(\"/bin/ls\").syscall { printf(\"|%d\", \$syscall) }"}
set syscall_return_script {"probe process(\"/bin/ls\").syscall.return { printf(\"|%d\", \$syscall) }"}
-set exec_script {"probe process(\"/bin/ls\").exec { print(\"ls exec\") }"}
+set thread_begin_script {"probe process(\"/bin/ls\").thread.begin { print(\"ls thread.begin\") }"}
+set thread_end_script {"probe process(\"/bin/ls\").thread.end { print(\"ls thread.end\") }"}
# Try to find utrace_attach symbol in /proc/kallsyms
set path "/proc/kallsyms"
@@ -69,16 +70,16 @@ set TEST_NAME "UTRACE_P4_01"
if {$utrace_support_found == 0} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
- # Try compiling a clone script
- stap_compile $TEST_NAME 1 $clone_script
+ # Try compiling a begin script
+ stap_compile $TEST_NAME 1 $begin_script
}
set TEST_NAME "UTRACE_P4_02"
if {$utrace_support_found == 0} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
- # Try compiling a death script
- stap_compile $TEST_NAME 1 $death_script
+ # Try compiling a end script
+ stap_compile $TEST_NAME 1 $end_script
}
set TEST_NAME "UTRACE_P4_03"
@@ -101,6 +102,14 @@ set TEST_NAME "UTRACE_P4_05"
if {$utrace_support_found == 0} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
- # Try compiling an exec script
- stap_compile $TEST_NAME 1 $exec_script
+ # Try compiling an thread.begin script
+ stap_compile $TEST_NAME 1 $thread_begin_script
+}
+
+set TEST_NAME "UTRACE_P4_06"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} else {
+ # Try compiling an thread.end script
+ stap_compile $TEST_NAME 1 $thread_end_script
}
diff --git a/testsuite/systemtap.base/utrace_p5.exp b/testsuite/systemtap.base/utrace_p5.exp
index cbb867d1..46e3181b 100644
--- a/testsuite/systemtap.base/utrace_p5.exp
+++ b/testsuite/systemtap.base/utrace_p5.exp
@@ -4,23 +4,23 @@
set utrace_support_found 0
set exepath "[pwd]/cat_[pid]"
-set death_script {
- global death_probes_fired = 0
+set end_script {
+ global end_probes_fired = 0
probe begin { printf("systemtap starting probe\n") }
- probe process("%s").death { death_probes_fired++ }
+ probe process("%s").end { end_probes_fired++ }
probe end { printf("systemtap ending probe\n")
- printf("deaths = %%d\n", death_probes_fired) }
+ printf("end probes = %%d\n", end_probes_fired) }
}
-set death_script_output "deaths = 1\r\n"
+set end_script_output "end probes = 1\r\n"
-set exec_script {
- global exec_probes_fired = 0
+set begin_script {
+ global begin_probes_fired = 0
probe begin { printf("systemtap starting probe\n") }
- probe process("%s").exec { exec_probes_fired++ }
+ probe process("%s").begin { begin_probes_fired++ }
probe end { printf("systemtap ending probe\n")
- printf("execs = %%d\n", exec_probes_fired) }
+ printf("begin probes = %%d\n", begin_probes_fired) }
}
-set exec_script_output "execs = 1\r\n"
+set begin_script_output "begin probes = 1\r\n"
set syscall_script {
global syscall_probes_fired = 0
@@ -46,18 +46,6 @@ set syscall_return_script {
}
set syscall_return_script_output "syscall_returns = \\d+\r\n"
-set clone_script {
- global clone_probes_fired = 0
- probe begin { printf("systemtap starting probe\n") }
- probe process(%d).clone { clone_probes_fired++ }
- probe end { printf("systemtap ending probe\n")
- if (clone_probes_fired > 0) {
- printf("clones = %%d\n", clone_probes_fired)
- }
- }
-}
-set clone_script_output "clones = \\d+\r\n"
-
# Try to find utrace_attach symbol in /proc/kallsyms
set path "/proc/kallsyms"
if {! [catch {exec grep -q utrace_attach $path} dummy]} {
@@ -92,8 +80,8 @@ if {$utrace_support_found == 0} {
} elseif {![installtest_p]} {
untested "$TEST_NAME"
} else {
- set script [format $death_script $exepath]
- stap_run $TEST_NAME run_cat_5_sec $death_script_output -e $script
+ set script [format $end_script $exepath]
+ stap_run $TEST_NAME run_cat_5_sec $end_script_output -e $script
}
set TEST_NAME "UTRACE_P5_02"
@@ -102,8 +90,8 @@ if {$utrace_support_found == 0} {
} elseif {![installtest_p]} {
untested "$TEST_NAME"
} else {
- set script [format $exec_script $exepath]
- stap_run $TEST_NAME run_cat_5_sec $exec_script_output -e $script
+ set script [format $begin_script $exepath]
+ stap_run $TEST_NAME run_cat_5_sec $begin_script_output -e $script
}
set TEST_NAME "UTRACE_P5_03"
@@ -126,15 +114,7 @@ if {$utrace_support_found == 0} {
stap_run $TEST_NAME run_cat_5_sec $syscall_return_script_output -e $script
}
-set TEST_NAME "UTRACE_P5_05"
-if {$utrace_support_found == 0} {
- untested "$TEST_NAME : no kernel utrace support found"
-} elseif {![installtest_p]} {
- untested "$TEST_NAME"
-} else {
- set script [format $clone_script [pid]]
- stap_run $TEST_NAME run_cat_5_sec $clone_script_output -e $script
-}
+# We need thread.begin and thread.end tests!
# Cleanup
exec rm -f $exepath