This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / kernel / utrace.c
diff --git a/kernel/utrace.c b/kernel/utrace.c
new file mode 100644 (file)
index 0000000..52d9b00
--- /dev/null
@@ -0,0 +1,1598 @@
+#include <linux/utrace.h>
+#include <linux/tracehook.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/tracehook.h>
+
+
+static kmem_cache_t *utrace_cachep;
+static kmem_cache_t *utrace_engine_cachep;
+
+static int __init
+utrace_init(void)
+{
+       utrace_cachep =
+               kmem_cache_create("utrace_cache",
+                                 sizeof(struct utrace), 0,
+                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+       utrace_engine_cachep =
+               kmem_cache_create("utrace_engine_cache",
+                                 sizeof(struct utrace_attached_engine), 0,
+                                 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+       return 0;
+}
+subsys_initcall(utrace_init);
+
+
+/*
+ * Make sure target->utrace is allocated, and return with it locked on
+ * success.  This function mediates startup races.  The creating parent
+ * task has priority, and other callers will delay here to let its call
+ * succeed and take the new utrace lock first.
+ */
+static struct utrace *
+utrace_first_engine(struct task_struct *target,
+                   struct utrace_attached_engine *engine)
+{
+       struct utrace *utrace, *ret;
+
+       /*
+        * If this is a newborn thread and we are not the creator,
+        * we have to wait for it.  The creator gets the first chance
+        * to attach.  The PF_STARTING flag is cleared after its
+        * report_clone hook has had a chance to run.
+        */
+       if ((target->flags & PF_STARTING)
+           && (current->utrace == NULL
+               || current->utrace->u.live.cloning != target)) {
+               yield();
+               return (signal_pending(current)
+                       ? ERR_PTR(-ERESTARTNOINTR) : NULL);
+       }
+
+       utrace = kmem_cache_alloc(utrace_cachep, SLAB_KERNEL);
+       if (unlikely(utrace == NULL))
+               return ERR_PTR(-ENOMEM);
+
+       utrace->u.live.cloning = NULL;
+       utrace->u.live.signal = NULL;
+       INIT_LIST_HEAD(&utrace->engines);
+       list_add(&engine->entry, &utrace->engines);
+       spin_lock_init(&utrace->lock);
+
+       ret = utrace;
+       utrace_lock(utrace);
+       task_lock(target);
+       if (likely(target->utrace == NULL)) {
+               rcu_assign_pointer(target->utrace, utrace);
+               /*
+                * The task_lock protects us against another thread doing
+                * the same thing.  We might still be racing against
+                * tracehook_release_task.  It's called with ->exit_state
+                * set to EXIT_DEAD and then checks ->utrace with an
+                * smp_mb() in between.  If EXIT_DEAD is set, then
+                * release_task might have checked ->utrace already and saw
+                * it NULL; we can't attach.  If we see EXIT_DEAD not yet
+                * set after our barrier, then we know release_task will
+                * see our target->utrace pointer.
+                */
+               smp_mb();
+               if (target->exit_state == EXIT_DEAD) {
+                       /*
+                        * The target has already been through release_task.
+                        */
+                       target->utrace = NULL;
+                       goto cannot_attach;
+               }
+               task_unlock(target);
+
+               /*
+                * If the thread is already dead when we attach, then its
+                * parent was notified already and we shouldn't repeat the
+                * notification later after a detach or NOREAP flag change.
+                */
+               if (target->exit_state)
+                       utrace->u.exit.notified = 1;
+       }
+       else {
+               /*
+                * Another engine attached first, so there is a struct already.
+                * A null return says to restart looking for the existing one.
+                */
+       cannot_attach:
+               ret = NULL;
+               task_unlock(target);
+               utrace_unlock(utrace);
+               kmem_cache_free(utrace_cachep, utrace);
+       }
+
+       return ret;
+}
+
+static void
+utrace_free(struct rcu_head *rhead)
+{
+       struct utrace *utrace = container_of(rhead, struct utrace, u.dead);
+       kmem_cache_free(utrace_cachep, utrace);
+}
+
+static void
+rcu_utrace_free(struct utrace *utrace)
+{
+       INIT_RCU_HEAD(&utrace->u.dead);
+       call_rcu(&utrace->u.dead, utrace_free);
+}
+
+static void
+utrace_engine_free(struct rcu_head *rhead)
+{
+       struct utrace_attached_engine *engine =
+               container_of(rhead, struct utrace_attached_engine, rhead);
+       kmem_cache_free(utrace_engine_cachep, engine);
+}
+
+/*
+ * Called with utrace locked and the target quiescent (maybe current).
+ * If this was the last engine, utrace is left locked and not freed,
+ * but is removed from the task.
+ */
+static void
+remove_engine(struct utrace_attached_engine *engine,
+             struct task_struct *tsk, struct utrace *utrace)
+{
+       list_del_rcu(&engine->entry);
+       if (list_empty(&utrace->engines)) {
+               task_lock(tsk);
+               if (likely(tsk->utrace != NULL)) {
+                       rcu_assign_pointer(tsk->utrace, NULL);
+                       tsk->utrace_flags = 0;
+               }
+               task_unlock(tsk);
+       }
+       call_rcu(&engine->rhead, utrace_engine_free);
+}
+
+/*
+ * This is pointed to by the utrace struct, but it's really a private
+ * structure between utrace_get_signal and utrace_inject_signal.
+ */
+struct utrace_signal
+{
+       siginfo_t *const info;
+       struct k_sigaction *return_ka;
+       int signr;
+};
+
+/*
+ * Called with utrace locked, after remove_engine may have run.
+ * Passed the flags from all remaining engines, i.e. zero if none left.
+ * Install the flags in tsk->utrace_flags and return with utrace unlocked.
+ * If no engines are left, utrace is freed and we return NULL.
+ */
+static struct utrace *
+check_dead_utrace(struct task_struct *tsk, struct utrace *utrace,
+                unsigned long flags)
+{
+       if (flags) {
+               tsk->utrace_flags = flags;
+               utrace_unlock(utrace);
+               return utrace;
+       }
+
+       if (utrace->u.live.signal && utrace->u.live.signal->signr != 0) {
+               utrace_unlock(utrace);
+               return utrace;
+       }
+
+       utrace_unlock(utrace);
+       rcu_utrace_free(utrace);
+       return NULL;
+}
+
+
+
+/*
+ * Get the target thread to quiesce.  Return nonzero if it's already quiescent.
+ * Return zero if it will report a QUIESCE event soon.
+ * If interrupt is nonzero, wake it like a signal would so it quiesces ASAP.
+ * If interrupt is zero, just make sure it quiesces before going to user mode.
+ */
+static int
+quiesce(struct task_struct *target, int interrupt)
+{
+       int quiescent;
+
+       target->utrace_flags |= UTRACE_ACTION_QUIESCE;
+       read_barrier_depends();
+
+       quiescent = (target->exit_state
+                    || target->state & (TASK_TRACED | TASK_STOPPED));
+
+       if (!quiescent) {
+               spin_lock_irq(&target->sighand->siglock);
+               quiescent = (unlikely(target->exit_state)
+                            || unlikely(target->state
+                                        & (TASK_TRACED | TASK_STOPPED)));
+               if (!quiescent) {
+                       if (interrupt)
+                               signal_wake_up(target, 0);
+                       else {
+                               set_tsk_thread_flag(target, TIF_SIGPENDING);
+                               kick_process(target);
+                       }
+               }
+               spin_unlock_irq(&target->sighand->siglock);
+       }
+
+       return quiescent;
+}
+
+
+static struct utrace_attached_engine *
+matching_engine(struct utrace *utrace, int flags,
+               const struct utrace_engine_ops *ops, unsigned long data)
+{
+       struct utrace_attached_engine *engine;
+       list_for_each_entry_rcu(engine, &utrace->engines, entry) {
+               if ((flags & UTRACE_ATTACH_MATCH_OPS)
+                   && engine->ops != ops)
+                       continue;
+               if ((flags & UTRACE_ATTACH_MATCH_DATA)
+                   && engine->data != data)
+                       continue;
+               if (flags & UTRACE_ATTACH_EXCLUSIVE)
+                       engine = ERR_PTR(-EEXIST);
+               return engine;
+       }
+       return NULL;
+}
+
+/*
+  option to stop it?
+  option to match existing on ops, ops+data, return it; nocreate:lookup only
+ */
+struct utrace_attached_engine *
+utrace_attach(struct task_struct *target, int flags,
+            const struct utrace_engine_ops *ops, unsigned long data)
+{
+       struct utrace *utrace;
+       struct utrace_attached_engine *engine;
+
+restart:
+       rcu_read_lock();
+       utrace = rcu_dereference(target->utrace);
+       smp_rmb();
+       if (utrace == NULL) {
+               rcu_read_unlock();
+
+               if (!(flags & UTRACE_ATTACH_CREATE)) {
+                       return ERR_PTR(-ENOENT);
+               }
+
+               engine = kmem_cache_alloc(utrace_engine_cachep, SLAB_KERNEL);
+               if (unlikely(engine == NULL))
+                       return ERR_PTR(-ENOMEM);
+               engine->flags = 0;
+
+       first:
+               utrace = utrace_first_engine(target, engine);
+               if (IS_ERR(utrace)) {
+                       kmem_cache_free(utrace_engine_cachep, engine);
+                       return ERR_PTR(PTR_ERR(utrace));
+               }
+               if (unlikely(utrace == NULL)) /* Race condition.  */
+                       goto restart;
+       }
+       else if (unlikely(target->exit_state == EXIT_DEAD)) {
+               /*
+                * The target has already been reaped.
+                */
+               rcu_read_unlock();
+               return ERR_PTR(-ESRCH);
+       }
+       else {
+               if (!(flags & UTRACE_ATTACH_CREATE)) {
+                       engine = matching_engine(utrace, flags, ops, data);
+                       rcu_read_unlock();
+                       return engine;
+               }
+
+               engine = kmem_cache_alloc(utrace_engine_cachep, SLAB_KERNEL);
+               if (unlikely(engine == NULL))
+                       return ERR_PTR(-ENOMEM);
+               engine->flags = ops->report_reap ? UTRACE_EVENT(REAP) : 0;
+
+               rcu_read_lock();
+               utrace = rcu_dereference(target->utrace);
+               if (unlikely(utrace == NULL)) { /* Race with detach.  */
+                       rcu_read_unlock();
+                       goto first;
+               }
+
+               utrace_lock(utrace);
+               if (flags & UTRACE_ATTACH_EXCLUSIVE) {
+                       struct utrace_attached_engine *old;
+                       old = matching_engine(utrace, flags, ops, data);
+                       if (old != NULL) {
+                               utrace_unlock(utrace);
+                               rcu_read_unlock();
+                               kmem_cache_free(utrace_engine_cachep, engine);
+                               return ERR_PTR(-EEXIST);
+                       }
+               }
+
+               if (unlikely(rcu_dereference(target->utrace) != utrace)) {
+                       /*
+                        * We lost a race with other CPUs doing a sequence
+                        * of detach and attach before we got in.
+                        */
+                       utrace_unlock(utrace);
+                       rcu_read_unlock();
+                       kmem_cache_free(utrace_engine_cachep, engine);
+                       goto restart;
+               }
+               list_add_tail_rcu(&engine->entry, &utrace->engines);
+       }
+
+       engine->ops = ops;
+       engine->data = data;
+
+       utrace_unlock(utrace);
+
+       return engine;
+}
+EXPORT_SYMBOL_GPL(utrace_attach);
+
+/*
+ * When an engine is detached, the target thread may still see it and make
+ * callbacks until it quiesces.  We reset its event flags to just QUIESCE
+ * and install a special ops vector whose callback is dead_engine_delete.
+ * When the target thread quiesces, it can safely free the engine itself.
+ */
+static u32
+dead_engine_delete(struct utrace_attached_engine *engine,
+                  struct task_struct *tsk)
+{
+       return UTRACE_ACTION_DETACH;
+}
+
+static const struct utrace_engine_ops dead_engine_ops =
+{
+       .report_quiesce = &dead_engine_delete
+};
+
+
+/*
+ * If tracing was preventing a SIGCHLD or self-reaping
+ * and is no longer, do that report or reaping right now.
+ */
+static void
+check_noreap(struct task_struct *target, struct utrace *utrace,
+            u32 old_action, u32 action)
+{
+       if ((action | ~old_action) & UTRACE_ACTION_NOREAP)
+               return;
+
+       if (utrace && xchg(&utrace->u.exit.notified, 1))
+               return;
+
+       if (target->exit_signal == -1)
+               release_task(target);
+       else if (thread_group_empty(target)) {
+               read_lock(&tasklist_lock);
+               do_notify_parent(target, target->exit_signal);
+               read_unlock(&tasklist_lock);
+       }
+}
+
+/*
+ * We may have been the one keeping the target thread quiescent.
+ * Check if it should wake up now.
+ * Called with utrace locked, and unlocks it on return.
+ * If we were keeping it stopped, resume it.
+ * If we were keeping its zombie from reporting/self-reap, do it now.
+ */
+static void
+wake_quiescent(unsigned long old_flags,
+              struct utrace *utrace, struct task_struct *target)
+{
+       unsigned long flags;
+       struct utrace_attached_engine *engine;
+
+       if (target->exit_state) {
+               /*
+                * Update the set of events of interest from the union
+                * of the interests of the remaining tracing engines.
+                */
+               flags = 0;
+               list_for_each_entry(engine, &utrace->engines, entry)
+                       flags |= engine->flags | UTRACE_EVENT(REAP);
+               utrace = check_dead_utrace(target, utrace, flags);
+
+               check_noreap(target, utrace, old_flags, flags);
+               return;
+       }
+
+       /*
+        * Update the set of events of interest from the union
+        * of the interests of the remaining tracing engines.
+        */
+       flags = 0;
+       list_for_each_entry(engine, &utrace->engines, entry)
+               flags |= engine->flags | UTRACE_EVENT(REAP);
+       utrace = check_dead_utrace(target, utrace, flags);
+
+       if (flags & UTRACE_ACTION_QUIESCE)
+               return;
+
+       read_lock(&tasklist_lock);
+       if (!target->exit_state) {
+               /*
+                * The target is not dead and should not be in tracing stop
+                * any more.  Wake it unless it's in job control stop.
+                */
+               spin_lock_irq(&target->sighand->siglock);
+               if (target->signal->flags & SIGNAL_STOP_STOPPED) {
+                       int stop_count = target->signal->group_stop_count;
+                       target->state = TASK_STOPPED;
+                       spin_unlock_irq(&target->sighand->siglock);
+
+                       /*
+                        * If tracing was preventing a CLD_STOPPED report
+                        * and is no longer, do that report right now.
+                        */
+                       if (stop_count == 0
+                           && 0
+                           /*&& (events &~ interest) & UTRACE_INHIBIT_CLDSTOP*/
+                               )
+                               do_notify_parent_cldstop(target, CLD_STOPPED);
+               }
+               else {
+                       /*
+                        * Wake the task up.
+                        */
+                       recalc_sigpending_tsk(target);
+                       wake_up_state(target, TASK_STOPPED | TASK_TRACED);
+                       spin_unlock_irq(&target->sighand->siglock);
+               }
+       }
+       read_unlock(&tasklist_lock);
+}
+
+void
+utrace_detach(struct task_struct *target,
+             struct utrace_attached_engine *engine)
+{
+       struct utrace *utrace;
+       unsigned long flags;
+
+       rcu_read_lock();
+       utrace = rcu_dereference(target->utrace);
+       smp_rmb();
+       if (unlikely(target->exit_state == EXIT_DEAD)) {
+               /*
+                * Called after utrace_release_task might have started.
+                * A call to this engine's report_reap callback might
+                * already be in progress or engine might even have been
+                * freed already.
+                */
+               rcu_read_unlock();
+               return;
+       }
+       utrace_lock(utrace);
+       rcu_read_unlock();
+
+       flags = engine->flags;
+       engine->flags = UTRACE_EVENT(QUIESCE) | UTRACE_ACTION_QUIESCE;
+       rcu_assign_pointer(engine->ops, &dead_engine_ops);
+
+       if (quiesce(target, 1)) {
+               remove_engine(engine, target, utrace);
+               wake_quiescent(flags, utrace, target);
+       }
+       else
+               utrace_unlock(utrace);
+}
+EXPORT_SYMBOL_GPL(utrace_detach);
+
+
+/*
+ * Called with utrace->lock held.
+ * Notify and clean up all engines, then free utrace.
+ */
+static void
+utrace_reap(struct task_struct *target, struct utrace *utrace)
+{
+       struct utrace_attached_engine *engine, *next;
+       const struct utrace_engine_ops *ops;
+
+restart:
+       list_for_each_entry_safe(engine, next, &utrace->engines, entry) {
+               list_del_rcu(&engine->entry);
+
+               /*
+                * Now nothing else refers to this engine.
+                */
+               if (engine->flags & UTRACE_EVENT(REAP)) {
+                       ops = rcu_dereference(engine->ops);
+                       if (ops != &dead_engine_ops) {
+                               utrace_unlock(utrace);
+                               (*ops->report_reap)(engine, target);
+                               call_rcu(&engine->rhead, utrace_engine_free);
+                               utrace_lock(utrace);
+                               goto restart;
+                       }
+               }
+               call_rcu(&engine->rhead, utrace_engine_free);
+       }
+       utrace_unlock(utrace);
+
+       rcu_utrace_free(utrace);
+}
+
+/*
+ * Called by release_task.  After this, target->utrace must be cleared.
+ */
+void
+utrace_release_task(struct task_struct *target)
+{
+       struct utrace *utrace;
+
+       task_lock(target);
+       utrace = target->utrace;
+       rcu_assign_pointer(target->utrace, NULL);
+       task_unlock(target);
+
+       if (unlikely(utrace == NULL))
+               return;
+
+       utrace_lock(utrace);
+
+       if (!utrace->u.exit.notified
+           && (target->utrace_flags & (UTRACE_EVENT(DEATH)
+                                       | UTRACE_EVENT(QUIESCE)))) {
+               /*
+                * The target will do some final callbacks but hasn't
+                * finished them yet.  We know because it clears these
+                * event bits after it's done.  Instead of cleaning up here
+                * and requiring utrace_report_death to cope with it, we
+                * delay the REAP report and the teardown until after the
+                * target finishes its death reports.
+                */
+               utrace->u.exit.reap = 1;
+               utrace_unlock(utrace);
+       }
+       else
+               utrace_reap(target, utrace); /* Unlocks and frees.  */
+}
+
+
+void
+utrace_set_flags(struct task_struct *target,
+                struct utrace_attached_engine *engine,
+                unsigned long flags)
+{
+       struct utrace *utrace;
+       int report = 0;
+       unsigned long old_flags, old_utrace_flags;
+
+#ifdef ARCH_HAS_SINGLE_STEP
+       if (! ARCH_HAS_SINGLE_STEP)
+#endif
+               WARN_ON(flags & UTRACE_ACTION_SINGLESTEP);
+#ifdef ARCH_HAS_BLOCK_STEP
+       if (! ARCH_HAS_BLOCK_STEP)
+#endif
+               WARN_ON(flags & UTRACE_ACTION_BLOCKSTEP);
+
+       rcu_read_lock();
+       utrace = rcu_dereference(target->utrace);
+       smp_rmb();
+       if (unlikely(target->exit_state == EXIT_DEAD)) {
+               /*
+                * Race with reaping.
+                */
+               rcu_read_unlock();
+               return;
+       }
+
+       utrace_lock(utrace);
+       rcu_read_unlock();
+
+       old_utrace_flags = target->utrace_flags;
+       old_flags = engine->flags;
+       engine->flags = flags;
+       target->utrace_flags |= flags;
+
+       if ((old_flags ^ flags) & UTRACE_ACTION_QUIESCE) {
+               if (flags & UTRACE_ACTION_QUIESCE) {
+                       report = (quiesce(target, 1)
+                                 && (flags & UTRACE_EVENT(QUIESCE)));
+                       utrace_unlock(utrace);
+               }
+               else
+                       wake_quiescent(old_flags, utrace, target);
+       }
+       else {
+               /*
+                * If we're asking for single-stepping or syscall tracing,
+                * we need to pass through utrace_quiescent before resuming
+                * in user mode to get those effects, even if the target is
+                * not going to be quiescent right now.
+                */
+               if (!(target->utrace_flags & UTRACE_ACTION_QUIESCE)
+                   && ((flags &~ old_utrace_flags)
+                       & (UTRACE_ACTION_SINGLESTEP | UTRACE_ACTION_BLOCKSTEP
+                          | UTRACE_EVENT_SYSCALL)))
+                       quiesce(target, 0);
+               utrace_unlock(utrace);
+       }
+
+       if (report)          /* Already quiescent, won't report itself.  */
+               (*engine->ops->report_quiesce)(engine, target);
+}
+EXPORT_SYMBOL_GPL(utrace_set_flags);
+\f
+/*
+ * While running an engine callback, no locks are held.
+ * If a callback updates its engine's action state, then
+ * we need to take the utrace lock to install the flags update.
+ */
+static inline u32
+update_action(struct task_struct *tsk, struct utrace *utrace,
+             struct utrace_attached_engine *engine,
+             u32 ret)
+{
+       if (ret & UTRACE_ACTION_DETACH)
+               rcu_assign_pointer(engine->ops, &dead_engine_ops);
+       else if ((ret & UTRACE_ACTION_NEWSTATE)
+                && ((ret ^ engine->flags) & UTRACE_ACTION_STATE_MASK)) {
+#ifdef ARCH_HAS_SINGLE_STEP
+               if (! ARCH_HAS_SINGLE_STEP)
+#endif
+                       WARN_ON(ret & UTRACE_ACTION_SINGLESTEP);
+#ifdef ARCH_HAS_BLOCK_STEP
+               if (! ARCH_HAS_BLOCK_STEP)
+#endif
+                       WARN_ON(ret & UTRACE_ACTION_BLOCKSTEP);
+               utrace_lock(utrace);
+               /*
+                * If we're changing something other than just QUIESCE,
+                * make sure we pass through utrace_quiescent before
+                * resuming even if we aren't going to stay quiescent.
+                * That's where we get the correct union of all engines'
+                * flags after they've finished changing, and apply changes.
+                */
+               if (((ret ^ engine->flags) & (UTRACE_ACTION_STATE_MASK
+                                             & ~UTRACE_ACTION_QUIESCE)))
+                       tsk->utrace_flags |= UTRACE_ACTION_QUIESCE;
+               engine->flags &= ~UTRACE_ACTION_STATE_MASK;
+               engine->flags |= ret & UTRACE_ACTION_STATE_MASK;
+               tsk->utrace_flags |= engine->flags;
+               utrace_unlock(utrace);
+       }
+       else
+               ret |= engine->flags & UTRACE_ACTION_STATE_MASK;
+       return ret;
+}
+
+#define REPORT(callback, ...) do { \
+       u32 ret = (*rcu_dereference(engine->ops)->callback) \
+               (engine, tsk, ##__VA_ARGS__); \
+       action = update_action(tsk, utrace, engine, ret); \
+       } while (0)
+
+
+/*
+ * Called with utrace->lock held, returns with it released.
+ */
+static u32
+remove_detached(struct task_struct *tsk, struct utrace *utrace,
+               struct utrace **utracep, u32 action)
+{
+       struct utrace_attached_engine *engine, *next;
+       unsigned long flags;
+
+       flags = 0;
+       list_for_each_entry_safe(engine, next, &utrace->engines, entry) {
+               if (engine->ops == &dead_engine_ops)
+                       remove_engine(engine, tsk, utrace);
+               else
+                       flags |= engine->flags | UTRACE_EVENT(REAP);
+       }
+       utrace = check_dead_utrace(tsk, utrace, flags);
+       if (utracep)
+               *utracep = utrace;
+
+       flags &= UTRACE_ACTION_STATE_MASK;
+       return flags | (action & UTRACE_ACTION_OP_MASK);
+}
+
+/*
+ * Called after an event report loop.  Remove any engines marked for detach.
+ */
+static inline u32
+check_detach(struct task_struct *tsk, u32 action)
+{
+       if (action & UTRACE_ACTION_DETACH) {
+               utrace_lock(tsk->utrace);
+               action = remove_detached(tsk, tsk->utrace, NULL, action);
+       }
+       return action;
+}
+
+static inline void
+check_quiescent(struct task_struct *tsk, u32 action)
+{
+       if (action & UTRACE_ACTION_STATE_MASK)
+               utrace_quiescent(tsk);
+}
+
+/*
+ * Called iff UTRACE_EVENT(CLONE) flag is set.
+ * This notification call blocks the wake_up_new_task call on the child.
+ * So we must not quiesce here.  tracehook_report_clone_complete will do
+ * a quiescence check momentarily.
+ */
+void
+utrace_report_clone(unsigned long clone_flags, struct task_struct *child)
+{
+       struct task_struct *tsk = current;
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       unsigned long action;
+
+       utrace->u.live.cloning = child;
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(CLONE))
+                       REPORT(report_clone, clone_flags, child);
+               if (action & UTRACE_ACTION_HIDE)
+                       break;
+       }
+
+       utrace->u.live.cloning = NULL;
+
+       check_detach(tsk, action);
+}
+
+static unsigned long
+report_quiescent(struct task_struct *tsk, struct utrace *utrace, u32 action)
+{
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(QUIESCE))
+                       REPORT(report_quiesce);
+               action |= engine->flags & UTRACE_ACTION_STATE_MASK;
+       }
+
+       return check_detach(tsk, action);
+}
+
+/*
+ * Called iff UTRACE_EVENT(JCTL) flag is set.
+ */
+int
+utrace_report_jctl(int what)
+{
+       struct task_struct *tsk = current;
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       unsigned long action;
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(JCTL))
+                       REPORT(report_jctl, what);
+               if (action & UTRACE_ACTION_HIDE)
+                       break;
+       }
+
+       /*
+        * We are becoming quiescent, so report it now.
+        * We don't block in utrace_quiescent because we are stopping anyway.
+        * We know that upon resuming we'll go through tracehook_induce_signal,
+        * which will keep us quiescent or set us up to resume with tracing.
+        */
+       action = report_quiescent(tsk, utrace, action);
+
+       if (what == CLD_STOPPED && tsk->state != TASK_STOPPED) {
+               /*
+                * The event report hooks could have blocked, though
+                * it should have been briefly.  Make sure we're in
+                * TASK_STOPPED state again to block properly, unless
+                * we've just come back out of job control stop.
+                */
+               spin_lock_irq(&tsk->sighand->siglock);
+               if (tsk->signal->flags & SIGNAL_STOP_STOPPED)
+                       set_current_state(TASK_STOPPED);
+               spin_unlock_irq(&tsk->sighand->siglock);
+       }
+
+       return action & UTRACE_JCTL_NOSIGCHLD;
+}
+
+
+/*
+ * Called if UTRACE_EVENT(QUIESCE) or UTRACE_ACTION_QUIESCE flag is set.
+ * Also called after other event reports.
+ * It is a good time to block.
+ */
+void
+utrace_quiescent(struct task_struct *tsk)
+{
+       struct utrace *utrace = tsk->utrace;
+       unsigned long action;
+
+restart:
+       /* XXX must change for sharing */
+
+       action = report_quiescent(tsk, utrace, UTRACE_ACTION_RESUME);
+
+       /*
+        * If some engines want us quiescent, we block here.
+        */
+       if (action & UTRACE_ACTION_QUIESCE) {
+               spin_lock_irq(&tsk->sighand->siglock);
+               /*
+                * If wake_quiescent is trying to wake us up now, it will
+                * have cleared the QUIESCE flag before trying to take the
+                * siglock.  Now we have the siglock, so either it has
+                * already cleared the flag, or it will wake us up after we
+                * release the siglock it's waiting for.
+                * Never stop when there is a SIGKILL bringing us down.
+                */
+               if ((tsk->utrace_flags & UTRACE_ACTION_QUIESCE)
+                   /*&& !(tsk->signal->flags & SIGNAL_GROUP_SIGKILL)*/) {
+                       set_current_state(TASK_TRACED);
+                       /*
+                        * If there is a group stop in progress,
+                        * we must participate in the bookkeeping.
+                        */
+                       if (tsk->signal->group_stop_count > 0)
+                               --tsk->signal->group_stop_count;
+                       spin_unlock_irq(&tsk->sighand->siglock);
+                       schedule();
+               }
+               else
+                       spin_unlock_irq(&tsk->sighand->siglock);
+
+               /*
+                * We've woken up.  One engine could be waking us up while
+                * another has asked us to quiesce.  So check afresh.  We
+                * could have been detached while quiescent.  Now we are no
+                * longer quiescent, so don't need to do any RCU locking.
+                * But we do need to check our utrace pointer anew.
+                */
+               utrace = tsk->utrace;
+               if (tsk->utrace_flags
+                   & (UTRACE_EVENT(QUIESCE) | UTRACE_ACTION_STATE_MASK))
+                       goto restart;
+       }
+       else if (tsk->utrace_flags & UTRACE_ACTION_QUIESCE) {
+               /*
+                * Our flags are out of date.
+                * Update the set of events of interest from the union
+                * of the interests of the remaining tracing engines.
+                */
+               struct utrace_attached_engine *engine;
+               unsigned long flags = 0;
+               utrace = rcu_dereference(tsk->utrace);
+               utrace_lock(utrace);
+               list_for_each_entry(engine, &utrace->engines, entry)
+                       flags |= engine->flags | UTRACE_EVENT(REAP);
+               tsk->utrace_flags = flags;
+               utrace_unlock(utrace);
+       }
+
+       /*
+        * We're resuming.  Update the machine layer tracing state and then go.
+        */
+#ifdef ARCH_HAS_SINGLE_STEP
+       if (action & UTRACE_ACTION_SINGLESTEP)
+               tracehook_enable_single_step(tsk);
+       else
+               tracehook_disable_single_step(tsk);
+#endif
+#ifdef ARCH_HAS_BLOCK_STEP
+       if ((action & (UTRACE_ACTION_BLOCKSTEP|UTRACE_ACTION_SINGLESTEP))
+           == UTRACE_ACTION_BLOCKSTEP)
+               tracehook_enable_block_step(tsk);
+       else
+               tracehook_disable_block_step(tsk);
+#endif
+       if (tsk->utrace_flags & UTRACE_EVENT_SYSCALL)
+               tracehook_enable_syscall_trace(tsk);
+       else
+               tracehook_disable_syscall_trace(tsk);
+}
+
+
+/*
+ * Called iff UTRACE_EVENT(EXIT) flag is set.
+ */
+void
+utrace_report_exit(long *exit_code)
+{
+       struct task_struct *tsk = current;
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       unsigned long action;
+       long orig_code = *exit_code;
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(EXIT))
+                       REPORT(report_exit, orig_code, exit_code);
+       }
+       action = check_detach(tsk, action);
+       check_quiescent(tsk, action);
+}
+
+/*
+ * Called iff UTRACE_EVENT(DEATH) flag is set.
+ *
+ * It is always possible that we are racing with utrace_release_task here,
+ * if UTRACE_ACTION_NOREAP is not set, or in the case of non-leader exec
+ * where the old leader will get released regardless of NOREAP.  For this
+ * reason, utrace_release_task checks for the event bits that get us here,
+ * and delays its cleanup for us to do.
+ */
+void
+utrace_report_death(struct task_struct *tsk, struct utrace *utrace)
+{
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       u32 action, oaction;
+
+       BUG_ON(!tsk->exit_state);
+
+       oaction = tsk->utrace_flags;
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(DEATH))
+                       REPORT(report_death);
+               if (engine->flags & UTRACE_EVENT(QUIESCE))
+                       REPORT(report_quiesce);
+       }
+       /*
+        * Unconditionally lock and recompute the flags.
+        * This may notice that there are no engines left and
+        * free the utrace struct.
+        */
+       utrace_lock(utrace);
+       if (utrace->u.exit.reap) {
+               /*
+                * utrace_release_task was already called in parallel.
+                * We must complete its work now.
+                */
+       reap:
+               utrace_reap(tsk, utrace);
+       }
+       else {
+               action = remove_detached(tsk, utrace, &utrace, action);
+
+               if (utrace != NULL) {
+                       utrace_lock(utrace);
+                       if (utrace->u.exit.reap)
+                               goto reap;
+
+                       /*
+                        * Clear event bits we can't see any more.  This
+                        * tells utrace_release_task we have already
+                        * finished, if it comes along later.
+                        */
+                       tsk->utrace_flags &= (UTRACE_EVENT(REAP)
+                                             | UTRACE_ACTION_NOREAP);
+
+                       utrace_unlock(utrace);
+               }
+
+               check_noreap(tsk, utrace, oaction, action);
+       }
+}
+
+/*
+ * Called iff UTRACE_EVENT(VFORK_DONE) flag is set.
+ */
+void
+utrace_report_vfork_done(pid_t child_pid)
+{
+       struct task_struct *tsk = current;
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       unsigned long action;
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(VFORK_DONE))
+                       REPORT(report_vfork_done, child_pid);
+               if (action & UTRACE_ACTION_HIDE)
+                       break;
+       }
+       action = check_detach(tsk, action);
+       check_quiescent(tsk, action);
+}
+
+/*
+ * Called iff UTRACE_EVENT(EXEC) flag is set.
+ */
+void
+utrace_report_exec(struct linux_binprm *bprm, struct pt_regs *regs)
+{
+       struct task_struct *tsk = current;
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       unsigned long action;
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & UTRACE_EVENT(EXEC))
+                       REPORT(report_exec, bprm, regs);
+               if (action & UTRACE_ACTION_HIDE)
+                       break;
+       }
+       action = check_detach(tsk, action);
+       check_quiescent(tsk, action);
+}
+
+/*
+ * Called iff UTRACE_EVENT(SYSCALL_{ENTRY,EXIT}) flag is set.
+ */
+void
+utrace_report_syscall(struct pt_regs *regs, int is_exit)
+{
+       struct task_struct *tsk = current;
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       unsigned long action, ev;
+
+/*
+  XXX pass syscall # to engine hook directly, let it return inhibit-action
+  to reset to -1
+       long syscall = tracehook_syscall_number(regs, is_exit);
+*/
+
+       ev = is_exit ? UTRACE_EVENT(SYSCALL_EXIT) : UTRACE_EVENT(SYSCALL_ENTRY);
+
+       /* XXX must change for sharing */
+       action = UTRACE_ACTION_RESUME;
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if (engine->flags & ev) {
+                       if (is_exit)
+                               REPORT(report_syscall_exit, regs);
+                       else
+                               REPORT(report_syscall_entry, regs);
+               }
+               if (action & UTRACE_ACTION_HIDE)
+                       break;
+       }
+       action = check_detach(tsk, action);
+       check_quiescent(tsk, action);
+}
+
+// XXX copied from signal.c
+#ifdef SIGEMT
+#define M_SIGEMT       M(SIGEMT)
+#else
+#define M_SIGEMT       0
+#endif
+
+#if SIGRTMIN > BITS_PER_LONG
+#define M(sig) (1ULL << ((sig)-1))
+#else
+#define M(sig) (1UL << ((sig)-1))
+#endif
+#define T(sig, mask) (M(sig) & (mask))
+
+#define SIG_KERNEL_ONLY_MASK (\
+       M(SIGKILL)   |  M(SIGSTOP)                                   )
+
+#define SIG_KERNEL_STOP_MASK (\
+       M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   )
+
+#define SIG_KERNEL_COREDUMP_MASK (\
+        M(SIGQUIT)   |  M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   | \
+        M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGBUS)    |  M(SIGSYS)    | \
+        M(SIGXCPU)   |  M(SIGXFSZ)   |  M_SIGEMT                     )
+
+#define SIG_KERNEL_IGNORE_MASK (\
+        M(SIGCONT)   |  M(SIGCHLD)   |  M(SIGWINCH)  |  M(SIGURG)    )
+
+#define sig_kernel_only(sig) \
+               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_COREDUMP_MASK))
+#define sig_kernel_ignore(sig) \
+               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_IGNORE_MASK))
+#define sig_kernel_stop(sig) \
+               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_STOP_MASK))
+
+
+/*
+ * Call each interested tracing engine's report_signal callback.
+ */
+static u32
+report_signal(struct task_struct *tsk, struct pt_regs *regs,
+             struct utrace *utrace, u32 action,
+             unsigned long flags1, unsigned long flags2, siginfo_t *info,
+             const struct k_sigaction *ka, struct k_sigaction *return_ka)
+{
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+
+       /* XXX must change for sharing */
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               if ((engine->flags & flags1) && (engine->flags & flags2)) {
+                       u32 disp = action & UTRACE_ACTION_OP_MASK;
+                       action &= ~UTRACE_ACTION_OP_MASK;
+                       REPORT(report_signal, regs, disp, info, ka, return_ka);
+                       if ((action & UTRACE_ACTION_OP_MASK) == 0)
+                               action |= disp;
+                       if (action & UTRACE_ACTION_HIDE)
+                               break;
+               }
+       }
+
+       return action;
+}
+
+void
+utrace_signal_handler_singlestep(struct task_struct *tsk, struct pt_regs *regs)
+{
+       u32 action;
+       action = report_signal(tsk, regs, tsk->utrace, UTRACE_SIGNAL_HANDLER,
+                              UTRACE_EVENT_SIGNAL_ALL,
+                              UTRACE_ACTION_SINGLESTEP|UTRACE_ACTION_BLOCKSTEP,
+                              NULL, NULL, NULL);
+       action = check_detach(tsk, action);
+       check_quiescent(tsk, action);
+}
+
+
+/*
+ * This is the hook from the signals code, called with the siglock held.
+ * Here is the ideal place to quiesce.  We also dequeue and intercept signals.
+ */
+int
+utrace_get_signal(struct task_struct *tsk, struct pt_regs *regs,
+                 siginfo_t *info, struct k_sigaction *return_ka)
+{
+       struct utrace *utrace = tsk->utrace;
+       struct utrace_signal signal = { info, return_ka, 0 };
+       struct k_sigaction *ka;
+       unsigned long action, event;
+
+#if 0                          /* XXX */
+       if (tsk->signal->flags & SIGNAL_GROUP_SIGKILL)
+               return 0;
+#endif
+
+       /*
+        * If we should quiesce, now is the time.
+        * First stash a pointer to the state on our stack,
+        * so that utrace_inject_signal can tell us what to do.
+        */
+       if (utrace->u.live.signal == NULL)
+               utrace->u.live.signal = &signal;
+
+       if (tsk->utrace_flags & UTRACE_ACTION_QUIESCE) {
+               spin_unlock_irq(&tsk->sighand->siglock);
+               utrace_quiescent(tsk);
+               if (signal.signr == 0)
+                       /*
+                        * This return value says to reacquire the siglock
+                        * and check again.  This will check for a pending
+                        * group stop and process it before coming back here.
+                        */
+                       return -1;
+               spin_lock_irq(&tsk->sighand->siglock);
+       }
+
+       /*
+        * If a signal was injected previously, it could not use our
+        * stack space directly.  It had to allocate a data structure,
+        * which we can now copy out of and free.
+        */
+       if (utrace->u.live.signal != &signal) {
+               signal.signr = utrace->u.live.signal->signr;
+               copy_siginfo(info, utrace->u.live.signal->info);
+               if (utrace->u.live.signal->return_ka)
+                       *return_ka = *utrace->u.live.signal->return_ka;
+               else
+                       signal.return_ka = NULL;
+               kfree(utrace->u.live.signal);
+       }
+       utrace->u.live.signal = NULL;
+
+       /*
+        * If a signal was injected, everything is in place now.  Go do it.
+        */
+       if (signal.signr != 0) {
+               if (signal.return_ka == NULL) {
+                       ka = &tsk->sighand->action[signal.signr - 1];
+                       if (ka->sa.sa_flags & SA_ONESHOT)
+                               ka->sa.sa_handler = SIG_DFL;
+                       *return_ka = *ka;
+               }
+               else
+                       BUG_ON(signal.return_ka != return_ka);
+               return signal.signr;
+       }
+
+       /*
+        * If noone is interested in intercepting signals, let the caller
+        * just dequeue them normally.
+        */
+       if ((tsk->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) == 0)
+               return 0;
+
+       /*
+        * Steal the next signal so we can let tracing engines examine it.
+        * From the signal number and sigaction, determine what normal
+        * delivery would do.  If no engine perturbs it, we'll do that
+        * by returning the signal number after setting *return_ka.
+        */
+       signal.signr = dequeue_signal(tsk, &tsk->blocked, info);
+       if (signal.signr == 0)
+               return 0;
+
+       BUG_ON(signal.signr != info->si_signo);
+
+       ka = &tsk->sighand->action[signal.signr - 1];
+       *return_ka = *ka;
+
+       if (signal.signr == SIGKILL)
+               return signal.signr;
+
+       if (ka->sa.sa_handler == SIG_IGN) {
+               event = UTRACE_EVENT(SIGNAL_IGN);
+               action = UTRACE_SIGNAL_IGN;
+       }
+       else if (ka->sa.sa_handler != SIG_DFL) {
+               event = UTRACE_EVENT(SIGNAL);
+               action = UTRACE_ACTION_RESUME;
+       }
+       else if (sig_kernel_coredump(signal.signr)) {
+               event = UTRACE_EVENT(SIGNAL_CORE);
+               action = UTRACE_SIGNAL_CORE;
+       }
+       else if (sig_kernel_ignore(signal.signr)) {
+               event = UTRACE_EVENT(SIGNAL_IGN);
+               action = UTRACE_SIGNAL_IGN;
+       }
+       else if (sig_kernel_stop(signal.signr)) {
+               event = UTRACE_EVENT(SIGNAL_STOP);
+               action = (signal.signr == SIGSTOP
+                         ? UTRACE_SIGNAL_STOP : UTRACE_SIGNAL_TSTP);
+       }
+       else {
+               event = UTRACE_EVENT(SIGNAL_TERM);
+               action = UTRACE_SIGNAL_TERM;
+       }
+
+       if (tsk->utrace_flags & event) {
+               /*
+                * We have some interested engines, so tell them about the
+                * signal and let them change its disposition.
+                */
+
+               spin_unlock_irq(&tsk->sighand->siglock);
+
+               action = report_signal(tsk, regs, utrace, action, event, event,
+                                      info, ka, return_ka);
+               action &= UTRACE_ACTION_OP_MASK;
+
+               if (action & UTRACE_SIGNAL_HOLD) {
+                       struct sigqueue *q = sigqueue_alloc();
+                       if (likely(q != NULL)) {
+                               q->flags = 0;
+                               copy_siginfo(&q->info, info);
+                       }
+                       action &= ~UTRACE_SIGNAL_HOLD;
+                       spin_lock_irq(&tsk->sighand->siglock);
+                       sigaddset(&tsk->pending.signal, info->si_signo);
+                       if (likely(q != NULL))
+                               list_add(&q->list, &tsk->pending.list);
+               }
+               else
+                       spin_lock_irq(&tsk->sighand->siglock);
+
+               recalc_sigpending_tsk(tsk);
+       }
+
+       if (tsk->utrace != utrace)
+               rcu_utrace_free(utrace);
+
+       /*
+        * We express the chosen action to the signals code in terms
+        * of a representative signal whose default action does it.
+        */
+       switch (action) {
+       case UTRACE_SIGNAL_IGN:
+               /*
+                * We've eaten the signal.  That's all we do.
+                * Tell the caller to restart.
+                */
+               spin_unlock_irq(&tsk->sighand->siglock);
+               return -1;
+
+       case UTRACE_ACTION_RESUME:
+       case UTRACE_SIGNAL_DELIVER:
+               /*
+                * The handler will run.  We do the SA_ONESHOT work here
+                * since the normal path will only touch *return_ka now.
+                */
+               if (return_ka->sa.sa_flags & SA_ONESHOT)
+                       ka->sa.sa_handler = SIG_DFL;
+               break;
+
+       case UTRACE_SIGNAL_TSTP:
+               signal.signr = SIGTSTP;
+               tsk->signal->flags |= SIGNAL_STOP_DEQUEUED;
+               return_ka->sa.sa_handler = SIG_DFL;
+               break;
+
+       case UTRACE_SIGNAL_STOP:
+               signal.signr = SIGSTOP;
+               tsk->signal->flags |= SIGNAL_STOP_DEQUEUED;
+               return_ka->sa.sa_handler = SIG_DFL;
+               break;
+
+       case UTRACE_SIGNAL_TERM:
+               signal.signr = SIGTERM;
+               return_ka->sa.sa_handler = SIG_DFL;
+               break;
+
+       case UTRACE_SIGNAL_CORE:
+               signal.signr = SIGQUIT;
+               return_ka->sa.sa_handler = SIG_DFL;
+               break;
+
+       default:
+               BUG();
+       }
+
+       return signal.signr;
+}
+
+
+/*
+ * Cause a specified signal delivery in the target thread,
+ * which must be quiescent.  The action has UTRACE_SIGNAL_* bits
+ * as returned from a report_signal callback.  If ka is non-null,
+ * it gives the sigaction to follow for UTRACE_SIGNAL_DELIVER;
+ * otherwise, the installed sigaction at the time of delivery is used.
+ */
+int
+utrace_inject_signal(struct task_struct *target,
+                   struct utrace_attached_engine *engine,
+                   u32 action, siginfo_t *info,
+                   const struct k_sigaction *ka)
+{
+       struct utrace *utrace;
+       struct utrace_signal *signal;
+       int ret;
+
+       if (info->si_signo == 0 || !valid_signal(info->si_signo))
+               return -EINVAL;
+
+       rcu_read_lock();
+       utrace = rcu_dereference(target->utrace);
+       if (utrace == NULL) {
+               rcu_read_unlock();
+               return -ESRCH;
+       }
+       utrace_lock(utrace);
+       rcu_read_unlock();
+
+       ret = 0;
+       signal = utrace->u.live.signal;
+       if (signal == NULL) {
+               ret = -ENOSYS;  /* XXX */
+       }
+       else if (signal->signr != 0)
+               ret = -EAGAIN;
+       else {
+               if (info != signal->info)
+                       copy_siginfo(signal->info, info);
+
+               switch (action) {
+               default:
+                       ret = -EINVAL;
+                       break;
+
+               case UTRACE_SIGNAL_IGN:
+                       break;
+
+               case UTRACE_ACTION_RESUME:
+               case UTRACE_SIGNAL_DELIVER:
+                       /*
+                        * The handler will run.  We do the SA_ONESHOT work
+                        * here since the normal path will not touch the
+                        * real sigaction when using an injected signal.
+                        */
+                       if (ka == NULL)
+                               signal->return_ka = NULL;
+                       else if (ka != signal->return_ka)
+                               *signal->return_ka = *ka;
+                       if (ka && ka->sa.sa_flags & SA_ONESHOT) {
+                               struct k_sigaction *a;
+                               a = &target->sighand->action[info->si_signo-1];
+                               spin_lock_irq(&target->sighand->siglock);
+                               a->sa.sa_handler = SIG_DFL;
+                               spin_unlock_irq(&target->sighand->siglock);
+                       }
+                       signal->signr = info->si_signo;
+                       break;
+
+               case UTRACE_SIGNAL_TSTP:
+                       signal->signr = SIGTSTP;
+                       spin_lock_irq(&target->sighand->siglock);
+                       target->signal->flags |= SIGNAL_STOP_DEQUEUED;
+                       spin_unlock_irq(&target->sighand->siglock);
+                       signal->return_ka->sa.sa_handler = SIG_DFL;
+                       break;
+
+               case UTRACE_SIGNAL_STOP:
+                       signal->signr = SIGSTOP;
+                       spin_lock_irq(&target->sighand->siglock);
+                       target->signal->flags |= SIGNAL_STOP_DEQUEUED;
+                       spin_unlock_irq(&target->sighand->siglock);
+                       signal->return_ka->sa.sa_handler = SIG_DFL;
+                       break;
+
+               case UTRACE_SIGNAL_TERM:
+                       signal->signr = SIGTERM;
+                       signal->return_ka->sa.sa_handler = SIG_DFL;
+                       break;
+
+               case UTRACE_SIGNAL_CORE:
+                       signal->signr = SIGQUIT;
+                       signal->return_ka->sa.sa_handler = SIG_DFL;
+                       break;
+               }
+       }
+
+       utrace_unlock(utrace);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(utrace_inject_signal);
+
+
+const struct utrace_regset *
+utrace_regset(struct task_struct *target,
+             struct utrace_attached_engine *engine,
+             const struct utrace_regset_view *view, int which)
+{
+       if (unlikely((unsigned) which >= view->n))
+               return NULL;
+
+       if (target != current)
+               wait_task_inactive(target);
+
+       return &view->regsets[which];
+}
+EXPORT_SYMBOL_GPL(utrace_regset);
+
+
+/*
+ * Return the task_struct for the task using ptrace on this one, or NULL.
+ * Must be called with rcu_read_lock held to keep the returned struct alive.
+ *
+ * At exec time, this may be called with task_lock(p) still held from when
+ * tracehook_unsafe_exec was just called.  In that case it must give
+ * results consistent with those unsafe_exec results, i.e. non-NULL if
+ * any LSM_UNSAFE_PTRACE_* bits were set.
+ *
+ * The value is also used to display after "TracerPid:" in /proc/PID/status,
+ * where it is called with only rcu_read_lock held.
+ */
+struct task_struct *
+utrace_tracer_task(struct task_struct *target)
+{
+       struct utrace *utrace;
+       struct task_struct *tracer = NULL;
+
+       utrace = rcu_dereference(target->utrace);
+       if (utrace != NULL) {
+               struct list_head *pos, *next;
+               struct utrace_attached_engine *engine;
+               const struct utrace_engine_ops *ops;
+               list_for_each_safe_rcu(pos, next, &utrace->engines) {
+                       engine = list_entry(pos, struct utrace_attached_engine,
+                                           entry);
+                       ops = rcu_dereference(engine->ops);
+                       if (ops->tracer_task) {
+                               tracer = (*ops->tracer_task)(engine, target);
+                               if (tracer != NULL)
+                                       break;
+                       }
+               }
+       }
+
+       return tracer;
+}
+
+int
+utrace_allow_access_process_vm(struct task_struct *target)
+{
+       struct utrace *utrace;
+       int ret = 0;
+
+       rcu_read_lock();
+       utrace = rcu_dereference(target->utrace);
+       if (utrace != NULL) {
+               struct list_head *pos, *next;
+               struct utrace_attached_engine *engine;
+               const struct utrace_engine_ops *ops;
+               list_for_each_safe_rcu(pos, next, &utrace->engines) {
+                       engine = list_entry(pos, struct utrace_attached_engine,
+                                           entry);
+                       ops = rcu_dereference(engine->ops);
+                       if (ops->allow_access_process_vm) {
+                               ret = (*ops->allow_access_process_vm)(engine,
+                                                                     target,
+                                                                     current);
+                               if (ret)
+                                       break;
+                       }
+               }
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
+/*
+ * Called on the current task to return LSM_UNSAFE_* bits implied by tracing.
+ * Called with task_lock held.
+ */
+int
+utrace_unsafe_exec(struct task_struct *tsk)
+{
+       struct utrace *utrace = tsk->utrace;
+       struct list_head *pos, *next;
+       struct utrace_attached_engine *engine;
+       const struct utrace_engine_ops *ops;
+       int unsafe = 0;
+
+       /* XXX must change for sharing */
+       list_for_each_safe_rcu(pos, next, &utrace->engines) {
+               engine = list_entry(pos, struct utrace_attached_engine, entry);
+               ops = rcu_dereference(engine->ops);
+               if (ops->unsafe_exec)
+                       unsafe |= (*ops->unsafe_exec)(engine, tsk);
+       }
+
+       return unsafe;
+}