[RFC PATCH 3/4] utrace core

From: Roland McGrath
Date: Tue Jun 13 2006 - 19:02:03 EST



This adds the utrace facility, a new modular interface in the kernel for
implementing user thread tracing and debugging. This fits on top of the
tracehook_* layer, so the new code is well-isolated.

The new interface is in <linux/utrace.h>, and Documentation/utrace.txt
describes it. It allows for multiple separate tracing engines to work in
parallel without interfering with each other. Higher-level tracing
facilities can be implemented as loadable kernel modules using this layer.

The new facility is made optional under CONFIG_UTRACE.
Normal configurations will always want to enable it.
It's optional to emphasize the clean separation of the code,
and in case some stripped-down embedded configurations might want to
omit it to save space (when ptrace and the like can never be used).

---

Documentation/utrace.txt | 451 +++++++++++++
arch/x86_64/kernel/ptrace.c | 13
include/linux/sched.h | 6
include/linux/tracehook.h | 124 +++-
include/linux/utrace.h | 459 +++++++++++++
init/Kconfig | 17
kernel/Makefile | 1
kernel/utrace.c | 1475 +++++++++++++++++++++++++++++++++++++++++++
8 files changed, 2522 insertions(+), 24 deletions(-)
create mode 100644 Documentation/utrace.txt
create mode 100644 include/linux/utrace.h
create mode 100644 kernel/utrace.c

diff --git a/Documentation/utrace.txt b/Documentation/utrace.txt
new file mode 100644
index ...155d477 100644
--- /dev/null
+++ b/Documentation/utrace.txt
@@ -0,0 +1,451 @@
+DRAFT DRAFT DRAFT WORK IN PROGRESS DRAFT DRAFT DRAFT
+
+This is work in progress and likely to change.
+
+
+ Roland McGrath <roland@xxxxxxxxxx>
+
+---
+
+ User Debugging Data & Event Rendezvous
+ ---- --------- ---- - ----- ----------
+
+See linux/utrace.h for all the declarations used here.
+See also linux/tracehook.h for the utrace_regset declarations.
+
+The UTRACE is infrastructure code for tracing and controlling user
+threads. This is the foundation for writing tracing engines, which
+can be loadable kernel modules. The UTRACE interfaces provide three
+basic facilities:
+
+* Thread event reporting
+
+ Tracing engines can request callbacks for events of interest in
+ the thread: signals, system calls, exit, exec, clone, etc.
+
+* Core thread control
+
+ Tracing engines can prevent a thread from running (keeping it in
+ TASK_TRACED state), or make it single-step or block-step (when
+ hardware supports it). Engines can cause a thread to abort system
+ calls, they change the behaviors of signals, and they can inject
+ signal-style actions at will.
+
+* Thread machine state access
+
+ Tracing engines can read and write a thread's registers and
+ similar per-thread CPU state.
+
+
+ Tracing engines
+ ------- -------
+
+The basic actors in UTRACE are the thread and the tracing engine.
+A tracing engine is some body of code that calls into the utrace_*
+interfaces, represented by a struct utrace_engine_ops. (Usually it's a
+kernel module, though the legacy ptrace support is a tracing engine
+that is not in a kernel module.) The UTRACE interface operates on
+individual threads (struct task_struct). If an engine wants to
+treat several threads as a group, that is up to its higher-level
+code. Using the UTRACE starts out by attaching an engine to a thread.
+
+ struct utrace_attached_engine *
+ utrace_attach(struct task_struct *target, int flags,
+ const struct utrace_engine_ops *ops, unsigned long data);
+
+Calling utrace_attach is what sets up a tracing engine to trace a
+thread. Use UTRACE_ATTACH_CREATE in flags, and pass your engine's ops.
+Check the return value with IS_ERR. If successful, it returns a
+struct pointer that is the handle used in all other utrace_* calls.
+The data argument is stored in the utrace_attached_engine structure,
+for your code to use however it wants.
+
+ void utrace_detach(struct task_struct *target,
+ struct utrace_attached_engine *engine);
+
+The utrace_detach call removes an engine from a thread.
+No more callbacks will be made after this returns.
+
+
+An attached engine does nothing by default.
+An engine makes something happen by setting its flags.
+
+ void utrace_set_flags(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ unsigned long flags);
+
+
+ Action Flags
+ ------ -----
+
+There are two kinds of flags that an attached engine can set: event
+flags, and action flags. Event flags register interest in particular
+events; when an event happens and an engine has the right event flag
+set, it gets a callback. Action flags change the normal behavior of
+the thread. The action flags available are:
+
+ UTRACE_ACTION_QUIESCE
+
+ The thread will stay quiescent (see below).
+ As long as any engine asserts the QUIESCE action flag,
+ the thread will not resume running in user mode.
+ (Usually it will be in TASK_TRACED state.)
+ Nothing will wake the thread up except for SIGKILL
+ (and implicit SIGKILLs such as a core dump in
+ another thread sharing the same address space, or a
+ group exit or fatal signal in another thread in the
+ same thread group).
+
+ UTRACE_ACTION_SINGLESTEP
+
+ When the thread runs, it will run one instruction
+ and then trap. (Exiting a system call or entering a
+ signal handler is considered "an instruction" for this.)
+
+ UTRACE_ACTION_BLOCKSTEP
+
+ When the thread runs, it will run until the next branch,
+ and then trap. (Exiting a system call or entering a
+ signal handler is considered a branch for this.)
+ When the SINGLESTEP flag is set, BLOCKSTEP has no effect.
+ This is only available on some machines (actually none yet).
+
+ UTRACE_ACTION_NOREAP
+
+ When the thread exits or stops for job control, its
+ parent process will not receive a SIGCHLD and the
+ parent's wait calls will not wake up or report the
+ child as dead. A well-behaved tracing engine does not
+ want to interfere with the parent's normal notifications.
+ This is provided mainly for the ptrace compatibility
+ code to implement the traditional behavior.
+
+Event flags are specified using the macro UTRACE_EVENT(TYPE).
+Each event type is associated with a report_* callback in struct
+utrace_engine_ops. A tracing engine can leave unused callbacks NULL.
+The only callbacks required are those used by the event flags it sets.
+
+Many engines can be attached to each thread. When a thread has an
+event, each engine gets a report_* callback if it has set the event flag
+for that event type. Engines are called in the order they attached.
+
+Each callback takes arguments giving the details of the particular
+event. The first two arguments two every callback are the struct
+utrace_attached_engine and struct task_struct pointers for the engine
+and the thread producing the event. Usually this will be the current
+thread that is running the callback functions.
+
+The return value of report_* callbacks is a bitmask. Some bits are
+common to all callbacks, and some are particular to that callback and
+event type. The value zero (UTRACE_ACTION_RESUME) always means the
+simplest thing: do what would have happened with no tracing engine here.
+These are the flags that can be set in any report_* return value:
+
+ UTRACE_ACTION_NEWSTATE
+
+ Update the action state flags, described above. Those
+ bits from the return value (UTRACE_ACTION_STATE_MASK)
+ replace those bits in the engine's flags. This has the
+ same effect as calling utrace_set_flags, but is a more
+ efficient short-cut. To change the event flags, you must
+ call utrace_set_flags.
+
+ UTRACE_ACTION_DETACH
+
+ Detach this engine. This has the effect of calling
+ utrace_detach, but is a more efficient short-cut.
+
+ UTRACE_ACTION_HIDE
+
+ Hide this event from other tracing engines. This is
+ only appropriate to do when the event was induced by
+ some action of this engine, such as a breakpoint trap.
+ Some events cannot be hidden, since every engine has to
+ know about them: exit, death, reap.
+
+The return value bits in UTRACE_ACTION_OP_MASK indicate a change to the
+normal behavior of the event taking place. If zero, the thread does
+whatever that event normally means. For report_signal, other values
+control the disposition of the signal.
+
+
+ Quiescence
+ ----------
+
+To control another thread and access its state, it must be "quiescent".
+This means that it is stopped and won't start running again while we access
+it. A quiescent thread is stopped in a place close to user mode, where the
+user state can be accessed safely; either it's about to return to user
+mode, or it's just entered the kernel from user mode, or it has already
+finished exiting (TASK_ZOMBIE). Setting the UTRACE_ACTION_QUIESCE action
+flag will force the attached thread to become quiescent soon. After
+setting the flag, an engine must wait for an event callback when the thread
+becomes quiescent. The thread may be running on another CPU, or may be in
+an uninterruptible wait. When it is ready to be examined, it will make
+callbacks to engines that set the UTRACE_EVENT(QUIESCE) event flag.
+
+As long as some engine has UTRACE_ACTION_QUIESCE set, then the thread will
+remain stopped. SIGKILL will wake it up, but it will not run user code.
+When the flag is cleared via utrace_set_flags or a callback return value,
+the thread starts running again.
+
+During the event callbacks (report_*), the thread in question makes the
+callback from a safe place. It is not quiescent, but it can safely access
+its own state. Callbacks can access thread state directly without setting
+the QUIESCE action flag. If a callback does want to prevent the thread
+from resuming normal execution, it *must* use the QUIESCE action state
+rather than simply blocking; see "Core Events & Callbacks", below.
+
+
+ Thread control
+ ------ -------
+
+These calls must be made on a quiescent thread (or the current thread):
+
+ int utrace_inject_signal(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ u32 action, siginfo_t *info,
+ const struct k_sigaction *ka);
+
+Cause a specified signal delivery in the target thread. This is not
+like kill, which generates a signal to be dequeued and delivered later.
+Injection directs the thread to deliver a signal now, before it next
+resumes in user mode or dequeues any other pending signal. It's as if
+the tracing engine intercepted a signal event and its report_signal
+callback returned the action argument as its value (see below). The
+info and ka arguments serve the same purposes as their counterparts in
+a report_signal callback.
+
+ const struct utrace_regset *
+ utrace_regset(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ const struct utrace_regset_view *view,
+ int which);
+
+Get access to machine state for the thread. The struct utrace_regset_view
+indicates a view of machine state, corresponding to a user mode
+architecture personality (such as 32-bit or 64-bit versions of a machine).
+The which argument selects one of the register sets available in that view.
+The utrace_regset call must be made before accessing any machine state,
+each time the thread has been running and has then become quiescent.
+It ensures that the thread's state is ready to be accessed, and returns
+the struct utrace_regset giving its accessor functions.
+
+XXX needs front ends for argument checks, export utrace_native_view
+
+
+ Core Events & Callbacks
+ ---- ------ - ---------
+
+Event reporting callbacks have details particular to the event type, but
+are all called in similar environments and have the same constraints.
+Callbacks are made from safe spots, where no locks are held, no special
+resources are pinned, and the user-mode state of the thread is accessible.
+So, callback code has a pretty free hand. But to be a good citizen,
+callback code should never block for long periods. It is fine to block in
+kmalloc and the like, but never wait for i/o or for user mode to do
+something. If you need the thread to wait, set UTRACE_ACTION_QUIESCE and
+return from the callback quickly. When your i/o finishes or whatever, you
+can use utrace_set_flags to resume the thread.
+
+Well-behaved callbacks are important to maintain two essential properties
+of the interface. The first of these is that unrelated tracing engines not
+interfere with each other. If your engine's event callback does not return
+quickly, then another engine won't get the event notification in a timely
+manner. The second important property is that tracing be as noninvasive as
+possible to the normal operation of the system overall and of the traced
+thread in particular. That is, attached tracing engines should not perturb
+a thread's behavior, except to the extent that changing its user-visible
+state is explicitly what you want to do. (Obviously some perturbation is
+unavoidable, primarily timing changes, ranging from small delays due to the
+overhead of tracing, to arbitrary pauses in user code execution when a user
+stops a thread with a debugger for examination. When doing asynchronous
+utrace_attach to a thread doing a system call, more troublesome side
+effects are possible.) Even when you explicitly want the pertrubation of
+making the traced thread block, just blocking directly in your callback has
+more unwanted effects. For example, the CLONE event callbacks are called
+when the new child thread has been created but not yet started running; the
+child can never be scheduled until the CLONE tracing callbacks return.
+(This allows engines tracing the parent to attach to the child.) If a
+CLONE event callback blocks the parent thread, it also prevents the child
+thread from running (even to process a SIGKILL). If what you want is to
+make both the parent and child block, then use utrace_attach on the child
+and then set the QUIESCE action state flag on both threads. A more crucial
+problem with blocking in callbacks is that it can prevent SIGKILL from
+working. A thread that is blocking due to UTRACE_ACTION_QUIESCE will still
+wake up and die immediately when sent a SIGKILL, as all threads should.
+Relying on the utrace infrastructure rather than on private synchronization
+calls in event callbacks is an important way to help keep tracing robustly
+noninvasive.
+
+
+EVENT(REAP) Dead thread has been reaped
+Callback:
+ void (*report_reap)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
+This means the parent called wait, or else this was a detached thread or
+a process whose parent ignores SIGCHLD. This cannot happen while the
+UTRACE_ACTION_NOREAP flag is set. This is the only callback you are
+guaranteed to get (if you set the flag).
+
+Unlike other callbacks, this can be called from the parent's context
+rather than from the traced thread itself--it must not delay the parent by
+blocking. This callback is different from all others, it returns void.
+Once you get this callback, your engine is automatically detached and you
+cannot access this thread or use this struct utrace_attached_engine handle
+any longer. This is the place to clean up your data structures and
+synchronize with your code that might try to make utrace_* calls using this
+engine data structure. The struct is still valid during this callback,
+but will be freed soon after it returns (via RCU).
+
+In all other callbacks, the return value is as described above.
+The common UTRACE_ACTION_* flags in the return value are always observed.
+Unless otherwise specified below, other bits in the return value are ignored.
+
+
+EVENT(QUIESCE) Thread is quiescent
+Callback:
+ u32 (*report_quiesce)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
+This is the least interesting callback. It happens at any safe spot,
+including after any other event callback. This lets the tracing engine
+know that it is safe to access the thread's state, or to report to users
+that it has stopped running user code.
+
+EVENT(CLONE) Thread is creating a child
+Callback:
+ u32 (*report_clone)(struct utrace_attached_engine *engine,
+ struct task_struct *parent,
+ unsigned long clone_flags,
+ struct task_struct *child);
+
+A clone/clone2/fork/vfork system call has succeeded in creating a new
+thread or child process. The new process is fully formed, but not yet
+running. During this callback, other tracing engines are prevented from
+using utrace_attach asynchronously on the child, so that engines tracing
+the parent get the first opportunity to attach. After this callback
+returns, the child will start and the parent's system call will return.
+If CLONE_VFORK is set, the parent will block before returning.
+
+EVENT(VFORK_DONE) Finished waiting for CLONE_VFORK child
+Callback:
+ u32 (*report_vfork_done)(struct utrace_attached_engine *engine,
+ struct task_struct *parent,
+ struct task_struct *child);
+
+Event reported for parent using CLONE_VFORK or vfork system call.
+The child has died or exec'd, so the vfork parent has unblocked
+and is about to return child->pid.
+
+UTRACE_EVENT(EXEC) Completed exec
+Callback:
+ u32 (*report_exec)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ const struct linux_binprm *bprm,
+ struct pt_regs *regs);
+
+An execve system call has succeeded and the new program is about to
+start running. The initial user register state is handy to be tweaked
+directly, or utrace_regset can be used for full machine state access.
+
+UTRACE_EVENT(EXIT) Thread is exiting
+Callback:
+ u32 (*report_exit)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ long orig_code, long *code);
+
+The thread is exiting and cannot be prevented from doing so, but all its
+state is still live. The *code value will be the wait result seen by
+the parent, and can be changed by this engine or others. The orig_code
+value is the real status, not changed by any tracing engine.
+
+UTRACE_EVENT(DEATH) Thread has finished exiting
+Callback:
+ u32 (*report_death)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
+The thread is really dead now. If the UTRACE_ACTION_NOREAP flag is set
+after this callback, it remains an unreported zombie. Otherwise, it
+might be reaped by its parent, or self-reap immediately.
+
+
+UTRACE_EVENT(SYSCALL_ENTRY) Thread has entered kernel for a system call
+Callback:
+ u32 (*report_syscall_entry)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs);
+
+The system call number and arguments can be seen and modified in the
+registers. The return value register has -ENOSYS, which will be
+returned for an invalid system call. The macro tracehook_abort_syscall(regs)
+will abort the system call so that we go immediately to syscall exit,
+and return -ENOSYS (or whatever the register state is changed to). If
+tracing enginges keep the thread quiescent here, the system call will
+not be performed until it resumes.
+
+UTRACE_EVENT(SYSCALL_EXIT) Thread is leaving kernel after a system call
+Callback:
+ u32 (*report_syscall_exit)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs);
+
+The return value can be seen and modified in the registers. If the
+thread is allowed to resume, it will see any pending signals and then
+return to user mode.
+
+UTRACE_EVENT(SIGNAL) Signal caught by user handler
+UTRACE_EVENT(SIGNAL_IGN) Signal with no effect (SIG_IGN or default)
+UTRACE_EVENT(SIGNAL_STOP) Job control stop signal
+UTRACE_EVENT(SIGNAL_TERM) Fatal termination signal
+UTRACE_EVENT(SIGNAL_CORE) Fatal core-dump signal
+UTRACE_EVENT_SIGNAL_ALL All of the above (bitmask)
+Callback:
+ u32 (*report_signal)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ u32 action, siginfo_t *info,
+ const struct k_sigaction *orig_ka,
+ struct k_sigaction *return_ka);
+
+There are five types of signal events, but all use the same callback.
+These happen when a thread is dequeuing a signal to be delivered.
+(Not immediately when the signal is sent, and not when the signal is
+blocked.) No signal event is reported for SIGKILL; no tracing engine
+can prevent it from killing the thread immediately. The specific
+event types allow an engine to trace signals based on what they do.
+UTRACE_EVENT_SIGNAL_ALL is all of them OR'd together, to trace all
+signals (except SIGKILL). A subset of these event flags can be used
+e.g. to catch only fatal signals, not handled ones, or to catch only
+core-dump signals, not normal termination signals.
+
+The action argument says what the signal's default disposition is:
+
+ UTRACE_SIGNAL_DELIVER Run the user handler from sigaction.
+ UTRACE_SIGNAL_IGN Do nothing, ignore the signal.
+ UTRACE_SIGNAL_TERM Terminate the process.
+ UTRACE_SIGNAL_CORE Terminate the process a write a core dump.
+ UTRACE_SIGNAL_STOP Absolutely stop the process, a la SIGSTOP.
+ UTRACE_SIGNAL_TSTP Job control stop (no stop if orphaned).
+
+This selection is made from consulting the process's sigaction and the
+default action for the signal number, but may already have been
+changed by an earlier tracing engine (in which case you see its override).
+A return value of UTRACE_ACTION_RESUME means to carry out this action.
+If instead UTRACE_SIGNAL_* bits are in the return value, that overrides
+the normal behavior of the signal.
+
+The signal number and other details of the signal are in info, and
+this data can be changed to make the thread see a different signal.
+A return value of UTRACE_SIGNAL_DELIVER says to follow the sigaction in
+return_ka, which can specify a user handler or SIG_IGN to ignore the
+signal or SIG_DFL to follow the default action for info->si_signo.
+The orig_ka parameter shows the process's sigaction at the time the
+signal was dequeued, and return_ka initially contains this. Tracing
+engines can modify return_ka to change the effects of delivery.
+For other UTRACE_SIGNAL_* return values, return_ka is ignored.
+
+UTRACE_SIGNAL_HOLD is a flag bit that can be OR'd into the return
+value. It says to push the signal back on the thread's queue, with
+the signal number and details possibly changed in info. When the
+thread is allowed to resume, it will dequeue and report it again.
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 28de290..71f716d 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -702,19 +702,6 @@ const struct utrace_regset_view utrace_x
EXPORT_SYMBOL_GPL(utrace_x86_64_native);


-static void syscall_trace(struct pt_regs *regs)
-{
-
-#if 0
- printk("trace %s rip %lx rsp %lx rax %d origrax %d caller %lx tiflags %x ptrace %x\n",
- current->comm,
- regs->rip, regs->rsp, regs->rax, regs->orig_rax, __builtin_return_address(0),
- current_thread_info()->flags, current->ptrace);
-#endif
-
- tracehook_report_syscall(regs, 1);
-}
-
asmlinkage void syscall_trace_enter(struct pt_regs *regs)
{
/* do the secure computing check first */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7894f20..b5ae996 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -811,6 +811,11 @@ struct task_struct {
struct audit_context *audit_context;
seccomp_t seccomp;

+#ifdef CONFIG_UTRACE
+ struct utrace *utrace;
+ unsigned long utrace_flags;
+#endif
+
/* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
@@ -917,6 +922,7 @@ static inline void put_task_struct(struc
#define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */
#define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */
#define PF_SWAPWRITE 0x01000000 /* Allowed to write to swap */
+#define PF_REAPED 0x02000000 /* release_task started */

/*
* Only the _current_ task can read/write to tsk->flags, but other
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 3262640..d0077b3 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -34,11 +34,12 @@ struct pt_regs;
* void tracehook_disable_single_step(struct task_struct *tsk);
* int tracehook_single_step_enabled(struct task_struct *tsk);
*
- * Block-step control (trap on control transfer), when available.
- * If these are available, asm/tracehook.h does #define HAVE_ARCH_BLOCK_STEP.
- * tracehook_disable_block_step will be called after tracehook_enable_single_step.
- * When enabled, the next jump, or other control transfer or syscall exit,
- * produces a SIGTRAP. Enabling or disabling redundantly is harmless.
+ * Block-step control (trap on control transfer), when available. If these
+ * are available, asm/tracehook.h does #define HAVE_ARCH_BLOCK_STEP.
+ * tracehook_disable_block_step will be called after
+ * tracehook_enable_single_step. When enabled, the next jump, or other
+ * control transfer or syscall exit, produces a SIGTRAP. Enabling or
+ * disabling redundantly is harmless.
*
* void tracehook_enable_block_step(struct task_struct *tsk);
* void tracehook_disable_block_step(struct task_struct *tsk);
@@ -167,12 +168,20 @@ struct ptrace_uarea_segment {
***
***/

+#ifdef CONFIG_UTRACE
+#include <linux/utrace.h>
+#endif
+
/*
* Return the value to display after "TracerPid:" in /proc/PID/status.
* Called without locks.
*/
static inline pid_t tracehook_tracer_pid(struct task_struct *p)
{
+#ifdef CONFIG_UTRACE
+ if (p->utrace_flags)
+ return utrace_tracer_pid(p);
+#endif
return 0;
}

@@ -182,6 +191,10 @@ static inline pid_t tracehook_tracer_pid
*/
static inline void tracehook_init_task(struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ child->utrace_flags = 0;
+ child->utrace = NULL;
+#endif
}

/*
@@ -190,6 +203,12 @@ static inline void tracehook_init_task(s
*/
static inline void tracehook_release_task(struct task_struct *p)
{
+#ifdef CONFIG_UTRACE
+ p->flags |= PF_REAPED;
+ smp_mb();
+ if (p->utrace != NULL)
+ utrace_release_task(p);
+#endif
}

/*
@@ -200,6 +219,9 @@ static inline void tracehook_release_tas
*/
static inline int tracehook_check_released(struct task_struct *p)
{
+#ifdef CONFIG_UTRACE
+ return unlikely(p->utrace != NULL);
+#endif
return 0;
}

@@ -211,6 +233,10 @@ static inline int tracehook_check_releas
static inline int tracehook_notify_cldstop(struct task_struct *tsk,
const siginfo_t *info)
{
+#ifdef CONFIG_UTRACE
+ if (tsk->utrace_flags & UTRACE_ACTION_NOREAP)
+ return 1;
+#endif
return 0;
}

@@ -223,6 +249,12 @@ static inline int tracehook_notify_cldst
*/
static inline int tracehook_notify_death(struct task_struct *tsk, int *noreap)
{
+#ifdef CONFIG_UTRACE
+ if (tsk->utrace_flags & UTRACE_ACTION_NOREAP) {
+ *noreap = 1;
+ return 1;
+ }
+#endif
*noreap = 0;
return 0;
}
@@ -235,6 +267,10 @@ static inline int tracehook_notify_death
static inline int tracehook_consider_fatal_signal(struct task_struct *tsk,
int sig)
{
+#ifdef CONFIG_UTRACE
+ return (tsk->utrace_flags & (UTRACE_EVENT(SIGNAL_TERM)
+ | UTRACE_EVENT(SIGNAL_CORE)));
+#endif
return 0;
}

@@ -247,6 +283,9 @@ static inline int tracehook_consider_fat
static inline int tracehook_consider_ignored_signal(struct task_struct *tsk,
int sig, void *handler)
{
+#ifdef CONFIG_UTRACE
+ return (tsk->utrace_flags & UTRACE_EVENT(SIGNAL_IGN));
+#endif
return 0;
}

@@ -258,6 +297,9 @@ static inline int tracehook_consider_ign
*/
static inline int tracehook_induce_sigpending(struct task_struct *tsk)
{
+#ifdef CONFIG_UTRACE
+ return unlikely(tsk->utrace_flags & UTRACE_ACTION_QUIESCE);
+#endif
return 0;
}

@@ -273,6 +315,10 @@ static inline int tracehook_get_signal(s
siginfo_t *info,
struct k_sigaction *return_ka)
{
+#ifdef CONFIG_UTRACE
+ if (unlikely(tsk->utrace_flags))
+ return utrace_get_signal(tsk, regs, info, return_ka);
+#endif
return 0;
}

@@ -285,6 +331,11 @@ static inline int tracehook_get_signal(s
*/
static inline int tracehook_finish_stop(int last_one)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & UTRACE_EVENT(JCTL))
+ return utrace_report_jctl(CLD_STOPPED);
+#endif
+
return 0;
}

@@ -306,6 +357,9 @@ static inline int tracehook_stop_now(voi
*/
static inline int tracehook_inhibit_wait_stopped(struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ return (child->utrace_flags & UTRACE_ACTION_NOREAP);
+#endif
return 0;
}

@@ -316,6 +370,9 @@ static inline int tracehook_inhibit_wait
*/
static inline int tracehook_inhibit_wait_zombie(struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ return (child->utrace_flags & UTRACE_ACTION_NOREAP);
+#endif
return 0;
}

@@ -326,6 +383,9 @@ static inline int tracehook_inhibit_wait
*/
static inline int tracehook_inhibit_wait_continued(struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ return (child->utrace_flags & UTRACE_ACTION_NOREAP);
+#endif
return 0;
}

@@ -363,6 +423,10 @@ static inline int tracehook_allow_access
{
if (tsk == current)
return 1;
+#ifdef CONFIG_UTRACE
+ if (tsk->utrace_flags)
+ return utrace_allow_access_process_vm(tsk);
+#endif
return 0;
}

@@ -383,14 +447,23 @@ static inline int tracehook_allow_access
*/
static inline void tracehook_report_death(struct task_struct *tsk)
{
+#ifdef CONFIG_UTRACE
+ if (tsk->utrace_flags & (UTRACE_EVENT(DEATH) | UTRACE_ACTION_QUIESCE))
+ utrace_report_death(tsk);
+#endif
}

/*
- * exec completed
+ * exec completed, we are shortly going to return to user mode.
+ * The freshly initialized register state can be seen and changed here.
*/
static inline void tracehook_report_exec(struct linux_binprm *bprm,
struct pt_regs *regs)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & UTRACE_EVENT(EXEC))
+ utrace_report_exec(bprm, regs);
+#endif
}

/*
@@ -399,6 +472,10 @@ static inline void tracehook_report_exec
*/
static inline void tracehook_report_exit(long *exit_code)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & UTRACE_EVENT(EXIT))
+ utrace_report_exit(exit_code);
+#endif
}

/*
@@ -413,19 +490,28 @@ static inline void tracehook_report_exit
static inline void tracehook_report_clone(unsigned long clone_flags,
struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & UTRACE_EVENT(CLONE))
+ utrace_report_clone(clone_flags, child);
+#endif
}

/*
- * Called after the child has started running, shortly after tracehook_report_clone.
- * This is just before the clone/fork syscall returns, or blocks for vfork
- * child completion if (clone_flags & CLONE_VFORK).
- * The child pointer may be invalid if a self-reaping child died and
- * tracehook_report_clone took no action to prevent it from self-reaping.
+ * Called after the child has started running, shortly after
+ * tracehook_report_clone. This is just before the clone/fork syscall
+ * returns, or blocks for vfork child completion if (clone_flags &
+ * CLONE_VFORK). The child pointer may be invalid if a self-reaping
+ * child died and tracehook_report_clone took no action to prevent it
+ * from self-reaping.
*/
static inline void tracehook_report_clone_complete(unsigned long clone_flags,
pid_t pid,
struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & UTRACE_ACTION_QUIESCE)
+ utrace_quiescent(current);
+#endif
}

/*
@@ -434,6 +520,10 @@ static inline void tracehook_report_clon
*/
static inline void tracehook_report_vfork_done(struct task_struct *child)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & UTRACE_EVENT(VFORK_DONE))
+ utrace_report_vfork_done(child);
+#endif
}

/*
@@ -441,6 +531,11 @@ static inline void tracehook_report_vfor
*/
static inline void tracehook_report_syscall(struct pt_regs *regs, int is_exit)
{
+#ifdef CONFIG_UTRACE
+ if (current->utrace_flags & (is_exit ? UTRACE_EVENT(SYSCALL_EXIT)
+ : UTRACE_EVENT(SYSCALL_ENTRY)))
+ utrace_report_syscall(regs, is_exit);
+#endif
}

/*
@@ -460,6 +555,13 @@ static inline void tracehook_report_hand
const sigset_t *oldset,
struct pt_regs *regs)
{
+#ifdef CONFIG_UTRACE
+ struct task_struct *tsk = current;
+ if ((tsk->utrace_flags & UTRACE_EVENT_SIGNAL_ALL)
+ && (tsk->utrace_flags & (UTRACE_ACTION_SINGLESTEP
+ | UTRACE_ACTION_BLOCKSTEP)))
+ utrace_signal_handler_singlestep(tsk, regs);
+#endif
}


diff --git a/include/linux/utrace.h b/include/linux/utrace.h
new file mode 100644
index ...6575c8a 100644
--- /dev/null
+++ b/include/linux/utrace.h
@@ -0,0 +1,459 @@
+/*
+ * User Debugging Data & Event Rendezvous
+ *
+ * This interface allows for notification of interesting events in a thread.
+ * It also mediates access to thread state such as registers.
+ * Multiple unrelated users can be associated with a single thread.
+ * We call each of these a tracing engine.
+ *
+ * A tracing engine starts by calling utrace_attach on the chosen thread,
+ * passing in a set of hooks (struct utrace_engine_ops), and some associated
+ * data. This produces a struct utrace_attached_engine, which is the handle
+ * used for all other operations. An attached engine has its ops vector,
+ * its data, and a flags word controlled by utrace_set_flags.
+ *
+ * Each engine's flags word contains two kinds of flags: events of
+ * interest, and action state flags.
+ *
+ * For each event flag that is set, that engine will get the
+ * appropriate ops->report_* callback when the event occurs. The
+ * struct utrace_engine_ops need not provide callbacks for an event
+ * unless the engine sets one of the associated event flags.
+ *
+ * Action state flags change the normal behavior of the thread.
+ * These bits are in UTRACE_ACTION_STATE_MASK; these can be OR'd into
+ * flags set with utrace_set_flags. Also, every callback that return
+ * an action value can reset these bits for the engine (see below).
+ *
+ * The bits UTRACE_ACTION_STATE_MASK of all attached engines are OR'd
+ * together, so each action is in force as long as any engine requests it.
+ * As long as some engine sets the UTRACE_ACTION_QUIESCE flag, the thread
+ * will block and not resume running user code. When the last engine
+ * clears its UTRACE_ACTION_QUIESCE flag, the thread will resume running.
+ */
+
+#ifndef _LINUX_UTRACE_H
+#define _LINUX_UTRACE_H 1
+
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+#include <linux/signal.h>
+
+struct linux_binprm;
+struct pt_regs;
+struct utrace_regset;
+struct utrace_regset_view;
+
+
+/*
+ * Flags in task_struct.utrace_flags and utrace_attached_engine.flags.
+ * Low four bits are UTRACE_ACTION_STATE_MASK bits (below).
+ * Higher bits are events of interest.
+ */
+
+#define UTRACE_FIRST_EVENT 4
+#define UTRACE_EVENT_BITS (BITS_PER_LONG - UTRACE_FIRST_EVENT)
+#define UTRACE_EVENT_MASK (-1UL &~ UTRACE_ACTION_STATE_MASK)
+
+enum utrace_events {
+ _UTRACE_EVENT_QUIESCE, /* Tracing requests stop. */
+ _UTRACE_EVENT_REAP, /* Zombie reaped, no more tracing possible. */
+ _UTRACE_EVENT_CLONE, /* Successful clone/fork/vfork just done. */
+ _UTRACE_EVENT_VFORK_DONE, /* vfork woke from waiting for child. */
+ _UTRACE_EVENT_EXEC, /* Successful execve just completed. */
+ _UTRACE_EVENT_EXIT, /* Thread exit in progress. */
+ _UTRACE_EVENT_DEATH, /* Thread has died. */
+ _UTRACE_EVENT_SYSCALL_ENTRY, /* User entered kernel for system call. */
+ _UTRACE_EVENT_SYSCALL_EXIT, /* Returning to user after system call. */
+ _UTRACE_EVENT_SIGNAL, /* Signal delivery will run a user handler. */
+ _UTRACE_EVENT_SIGNAL_IGN, /* No-op signal to be delivered. */
+ _UTRACE_EVENT_SIGNAL_STOP, /* Signal delivery will suspend. */
+ _UTRACE_EVENT_SIGNAL_TERM, /* Signal delivery will terminate. */
+ _UTRACE_EVENT_SIGNAL_CORE, /* Signal delivery will dump core. */
+ _UTRACE_EVENT_JCTL, /* Job control stop or continue completed. */
+ _UTRACE_NEVENTS
+};
+#define UTRACE_EVENT_BIT(type) (UTRACE_FIRST_EVENT + _UTRACE_EVENT_##type)
+#define UTRACE_EVENT(type) (1UL << UTRACE_EVENT_BIT(type))
+
+/*
+ * All the kinds of signal events. These all use the report_signal callback.
+ */
+#define UTRACE_EVENT_SIGNAL_ALL (UTRACE_EVENT(SIGNAL) \
+ | UTRACE_EVENT(SIGNAL_IGN) \
+ | UTRACE_EVENT(SIGNAL_STOP) \
+ | UTRACE_EVENT(SIGNAL_TERM) \
+ | UTRACE_EVENT(SIGNAL_CORE))
+/*
+ * Both kinds of syscall events; these call the report_syscall_entry and
+ * report_syscall_exit callbacks, respectively.
+ */
+#define UTRACE_EVENT_SYSCALL \
+ (UTRACE_EVENT(SYSCALL_ENTRY) | UTRACE_EVENT(SYSCALL_EXIT))
+
+
+/*
+ * Action flags, in return value of callbacks.
+ *
+ * UTRACE_ACTION_RESUME (zero) is the return value to do nothing special.
+ * For each particular callback, some bits in UTRACE_ACTION_OP_MASK can
+ * be set in the return value to change the thread's behavior (see below).
+ *
+ * If UTRACE_ACTION_NEWSTATE is set, then the UTRACE_ACTION_STATE_MASK
+ * bits in the return value replace the engine's flags as in utrace_set_flags
+ * (but the event flags remained unchanged).
+ *
+ * If UTRACE_ACTION_HIDE is set, then the callbacks to other engines
+ * should be suppressed for this event. This is appropriate only when
+ * the event was artificially provoked by something this engine did,
+ * such as setting a breakpoint.
+ *
+ * If UTRACE_ACTION_DETACH is set, this engine is detached as by utrace_detach.
+ * The action bits in UTRACE_ACTION_OP_MASK work as normal, but the engine's
+ * UTRACE_ACTION_STATE_MASK bits will no longer affect the thread.
+ */
+#define UTRACE_ACTION_RESUME 0x0000 /* Continue normally after event. */
+#define UTRACE_ACTION_HIDE 0x0010 /* Hide event from other tracing. */
+#define UTRACE_ACTION_DETACH 0x0020 /* Detach me, state flags ignored. */
+#define UTRACE_ACTION_NEWSTATE 0x0040 /* Replace state bits. */
+
+/*
+ * These flags affect the state of the thread until they are changed via
+ * utrace_set_flags or by the next callback to the same engine that uses
+ * UTRACE_ACTION_NEWSTATE.
+ */
+#define UTRACE_ACTION_QUIESCE 0x0001 /* Stay quiescent after callbacks. */
+#define UTRACE_ACTION_SINGLESTEP 0x0002 /* Resume for one instruction. */
+#define UTRACE_ACTION_BLOCKSTEP 0x0004 /* Resume until next branch. */
+#define UTRACE_ACTION_NOREAP 0x0008 /* Inhibit parent SIGCHLD and wait. */
+#define UTRACE_ACTION_STATE_MASK 0x000f /* Lasting state bits. */
+
+/* These flags have meanings specific to the particular event report hook. */
+#define UTRACE_ACTION_OP_MASK 0xff00
+
+/*
+ * Action flags in return value and argument of report_signal callback.
+ */
+#define UTRACE_SIGNAL_DELIVER 0x0100 /* Deliver according to sigaction. */
+#define UTRACE_SIGNAL_IGN 0x0200 /* Ignore the signal. */
+#define UTRACE_SIGNAL_TERM 0x0300 /* Terminate the process. */
+#define UTRACE_SIGNAL_CORE 0x0400 /* Terminate with core dump. */
+#define UTRACE_SIGNAL_STOP 0x0500 /* Deliver as absolute stop. */
+#define UTRACE_SIGNAL_TSTP 0x0600 /* Deliver as job control stop. */
+#define UTRACE_SIGNAL_HOLD 0x1000 /* Flag, push signal back on queue. */
+/*
+ * This value is passed to a report_signal callback after a signal
+ * handler is entered while UTRACE_ACTION_SINGLESTEP is in force.
+ * For this callback, no signal will never actually be delivered regardless
+ * of the return value, and the other callback parameters are null.
+ */
+#define UTRACE_SIGNAL_HANDLER 0x0700
+
+/* Action flag in return value of report_jctl. */
+#define UTRACE_JCTL_NOSIGCHLD 0x0100 /* Do not notify the parent. */
+
+
+/*
+ * Flags for utrace_attach. If UTRACE_ATTACH_CREATE is not specified,
+ * you only look up an existing engine already attached to the
+ * thread. If UTRACE_ATTACH_MATCH_* bits are set, only consider
+ * matching engines. If UTRACE_ATTACH_EXCLUSIVE is set, attempting to
+ * attach a second (matching) engine fails with -EEXIST.
+ */
+#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */
+#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */
+#define UTRACE_ATTACH_MATCH_OPS 0x0001 /* Match engines on ops. */
+#define UTRACE_ATTACH_MATCH_DATA 0x0002 /* Match engines on data. */
+#define UTRACE_ATTACH_MATCH_MASK 0x000f
+
+
+/*
+ * Per-thread structure task_struct.utrace points to.
+ *
+ * The task itself never has to worry about this going away after
+ * some event is found set in task_struct.utrace_flags.
+ * Once created, this pointer is changed only when the task is quiescent
+ * (TASK_TRACED or TASK_STOPPED with the siglock held, or dead).
+ *
+ * For other parties, the pointer to this is protected by RCU and
+ * task_lock. Since call_rcu is never used while the thread is alive and
+ * using this struct utrace, we can overlay the RCU data structure used
+ * only for a dead struct with some local state used only for a live utrace
+ * on an active thread.
+ */
+struct utrace
+{
+ union {
+ struct rcu_head dead;
+ struct {
+ struct task_struct *cloning;
+ struct utrace_signal *signal;
+ } live;
+ struct {
+ int notified;
+ } exit;
+ } u;
+
+ struct list_head engines;
+ spinlock_t lock;
+};
+#define utrace_lock(utrace) spin_lock(&(utrace)->lock)
+#define utrace_unlock(utrace) spin_unlock(&(utrace)->lock)
+
+
+/*
+ * Per-engine per-thread structure.
+ *
+ * The task itself never has to worry about engines detaching while
+ * it's doing event callbacks. These structures are freed only when
+ * the task is quiescent. For other parties, the list is protected
+ * by RCU and utrace_lock.
+ */
+struct utrace_attached_engine
+{
+ struct list_head entry; /* Entry on thread's utrace.engines list. */
+ struct rcu_head rhead;
+
+ const struct utrace_engine_ops *ops;
+ unsigned long data;
+
+ unsigned long flags;
+};
+
+
+struct utrace_engine_ops
+{
+ /*
+ * Event reporting hooks.
+ *
+ * Return values contain UTRACE_ACTION_* flag bits.
+ * The UTRACE_ACTION_OP_MASK bits are specific to each kind of event.
+ *
+ * All report_* hooks are called with no locks held, in a generally
+ * safe environment when we will be returning to user mode soon.
+ * It is fine to block for memory allocation and the like, but all
+ * hooks are *asynchronous* and must not block on external events.
+ * If you want the thread to block, request UTRACE_ACTION_QUIESCE in
+ * your hook; then later wake it up with utrace_set_flags.
+ *
+ */
+
+ /*
+ * Event reported for parent, before child might run.
+ * The PF_STARTING flag prevents other engines from attaching
+ * before this one has its chance.
+ */
+ u32 (*report_clone)(struct utrace_attached_engine *engine,
+ struct task_struct *parent,
+ unsigned long clone_flags,
+ struct task_struct *child);
+
+ /*
+ * Event reported for parent using CLONE_VFORK or vfork system call.
+ * The child has died or exec'd, so the vfork parent has unblocked
+ * and is about to return child->pid.
+ */
+ u32 (*report_vfork_done)(struct utrace_attached_engine *engine,
+ struct task_struct *parent,
+ struct task_struct *child);
+
+ /*
+ * Event reported after UTRACE_ACTION_QUIESCE is set, when the target
+ * thread is quiescent. Either it's the current thread, or it's in
+ * TASK_TRACED or TASK_STOPPED and will not resume running until the
+ * UTRACE_ACTION_QUIESCE flag is no longer asserted by any engine.
+ */
+ u32 (*report_quiesce)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
+ /*
+ * Thread dequeuing a signal to be delivered.
+ * The action and *return_ka values say what UTRACE_ACTION_RESUME
+ * will do (possibly already influenced by another tracing engine).
+ * An UTRACE_SIGNAL_* return value overrides the signal disposition.
+ * The *info data (including info->si_signo) can be changed at will.
+ * Changing *return_ka affects the sigaction that be used.
+ * The *orig_ka value is the one in force before other tracing
+ * engines intervened.
+ */
+ u32 (*report_signal)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs,
+ u32 action, siginfo_t *info,
+ const struct k_sigaction *orig_ka,
+ struct k_sigaction *return_ka);
+
+ /*
+ * Job control event completing, about to send SIGCHLD to parent
+ * with CLD_STOPPED or CLD_CONTINUED as given in type.
+ * UTRACE_JOBSTOP_NOSIGCHLD in the return value inhibits that.
+ */
+ u32 (*report_jctl)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ int type);
+
+ /*
+ * Thread has just completed an exec.
+ * The initial user register state is handy to be tweaked directly.
+ */
+ u32 (*report_exec)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ const struct linux_binprm *bprm,
+ struct pt_regs *regs);
+
+ /*
+ * Thread has entered the kernel to request a system call.
+ * The user register state is handy to be tweaked directly.
+ */
+ u32 (*report_syscall_entry)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs);
+
+ /*
+ * Thread is about to leave the kernel after a system call request.
+ * The user register state is handy to be tweaked directly.
+ */
+ u32 (*report_syscall_exit)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs);
+
+ /*
+ * Thread is exiting and cannot be prevented from doing so,
+ * but all its state is still live. The *code value will be
+ * the wait result seen by the parent, and can be changed by
+ * this engine or others. The orig_code value is the real
+ * status, not changed by any tracing engine.
+ */
+ u32 (*report_exit)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ long orig_code, long *code);
+
+ /*
+ * Thread is really dead now. If UTRACE_ACTION_NOREAP is in force,
+ * it remains an unreported zombie. Otherwise, it might be reaped
+ * by its parent, or self-reap immediately.
+ */
+ u32 (*report_death)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
+ /*
+ * Called when someone reaps the dead task (parent, init, or self).
+ * No more callbacks are made after this one.
+ * The engine is always detached.
+ * There is nothing more a tracing engine can do about this thread.
+ */
+ void (*report_reap)(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
+ /*
+ * Miscellaneous hooks. These are not associated with event reports.
+ * Any of these may be null if the engine has nothing to say.
+ * These hooks are called in more constrained environments and should
+ * not block or do very much.
+ */
+
+ /*
+ * Return nonzero iff the caller task should be allowed to access
+ * the memory of the target task via /proc/PID/mem and so forth,
+ * by dint of this engine's attachment to the target.
+ */
+ int (*allow_access_process_vm)(struct utrace_attached_engine *engine,
+ struct task_struct *target,
+ struct task_struct *caller);
+
+ /*
+ * Return the value to display after "TracerPid:" in /proc/PID/status.
+ * If this engine returns zero, another engine may supply the value.
+ */
+ pid_t (*tracer_pid)(struct utrace_attached_engine *engine,
+ struct task_struct *target);
+};
+
+
+/***
+ *** These are the exported entry points for tracing engines to use.
+ ***/
+
+/*
+ * Attach a new tracing engine to a thread, or look up attached engines.
+ * See UTRACE_ATTACH_* flags, above. The caller must ensure that the
+ * target thread does not get freed, i.e. hold a ref or be its parent.
+ */
+struct utrace_attached_engine *utrace_attach(struct task_struct *target,
+ int flags,
+ const struct utrace_engine_ops *,
+ unsigned long data);
+
+/*
+ * Detach a tracing engine from a thread. After this, the engine
+ * data structure is no longer accessible, and the thread might be reaped.
+ * The thread will start running again if it was being kept quiescent
+ * and no longer has any attached engines asserting UTRACE_ACTION_QUIESCE.
+ *
+ * If the target thread is not already quiescent, then a callback to this
+ * engine might be in progress or about to start on another CPU. If it's
+ * quiescent when utrace_detach is called, then after return it's guaranteed
+ * that no more callbacks to the ops vector will be done.
+ */
+void utrace_detach(struct task_struct *target,
+ struct utrace_attached_engine *engine);
+
+/*
+ * Change the flags for a tracing engine.
+ * This resets the event flags and the action state flags.
+ * If UTRACE_ACTION_QUIESCE and UTRACE_EVENT(QUIESCE) are set,
+ * this will cause a report_quiesce callback soon, maybe immediately.
+ * If UTRACE_ACTION_QUIESCE was set before and is no longer set by
+ * any engine, this will wake the thread up.
+ */
+void utrace_set_flags(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ unsigned long flags);
+
+/*
+ * Cause a specified signal delivery in the target thread, which must be
+ * quiescent (or the current thread). 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);
+
+/*
+ * Prepare to access thread's machine state, see <linux/tracehook.h>.
+ * The given thread must be quiescent (or the current thread).
+ * When this returns, the struct utrace_regset calls may be used to
+ * interrogate or change the thread's state. Do not cache the returned
+ * pointer when the thread can resume. You must call utrace_regset to
+ * ensure that context switching has completed and consistent state is
+ * available.
+ */
+const struct utrace_regset *utrace_regset(struct task_struct *target,
+ struct utrace_attached_engine *,
+ const struct utrace_regset_view *,
+ int which);
+
+
+/*
+ * Hooks in <linux/tracehook.h> call these entry points to the utrace dispatch.
+ */
+void utrace_quiescent(struct task_struct *);
+void utrace_release_task(struct task_struct *);
+int utrace_get_signal(struct task_struct *, struct pt_regs *,
+ siginfo_t *, struct k_sigaction *);
+void utrace_report_clone(unsigned long clone_flags, struct task_struct *child);
+void utrace_report_vfork_done(struct task_struct *child);
+void utrace_report_exit(long *exit_code);
+void utrace_report_death(struct task_struct *);
+int utrace_report_jctl(int type);
+void utrace_report_exec(struct linux_binprm *bprm, struct pt_regs *regs);
+void utrace_report_syscall(struct pt_regs *regs, int is_exit);
+pid_t utrace_tracer_pid(struct task_struct *);
+int utrace_allow_access_process_vm(struct task_struct *);
+void utrace_signal_handler_singlestep(struct task_struct *, struct pt_regs *);
+
+
+#endif /* linux/utrace.h */
diff --git a/init/Kconfig b/init/Kconfig
index 38416a1..21d6806 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -511,6 +511,23 @@ config STOP_MACHINE
Need stop_machine() primitive.
endmenu

+menu "Process debugging support"
+
+config UTRACE
+ bool "Infrastructure for tracing and debugging user processes"
+ default y
+ help
+ Enable the utrace process tracing interface.
+ This is an internal kernel interface to track events in user
+ threads, extract and change user thread state. This interface
+ is exported to kernel modules, and is also used to implement ptrace.
+ If you disable this, no facilities for debugging user processes
+ will be available, nor the facilities used by UML and other
+ applications. Unless you are making a specially stripped-down
+ kernel and are very sure you don't need these facilitiies,
+ say Y.
+endmenu
+
menu "Block layer"
source "block/Kconfig"
endmenu
diff --git a/kernel/Makefile b/kernel/Makefile
index 4ae0fbd..4bb2f60 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softl
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
+obj-$(CONFIG_UTRACE) += utrace.o

ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@xxxxxxxxxxxxxxxx>, the -fno-omit-frame-pointer is
diff --git a/kernel/utrace.c b/kernel/utrace.c
new file mode 100644
index ...d18eba0 100644
--- /dev/null
+++ b/kernel/utrace.c
@@ -0,0 +1,1475 @@
+#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 sets PF_REAPED and then
+ * checks ->utrace with an smp_mb() in between. If
+ * PF_REAPED is set, then release_task might have checked
+ * ->utrace already and saw it NULL; we can't attach. If
+ * we see PF_REAPED not yet set after our barrier, then we
+ * know release_task will see our target->utrace pointer.
+ */
+ smp_mb();
+ if (target->flags & PF_REAPED) {
+ /*
+ * 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);
+}
+
+
+/*
+ * 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;
+ }
+
+ 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->flags & PF_REAPED)) {
+ /*
+ * The target has already been through release_task.
+ */
+ 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->flags & PF_REAPED)) {
+ /*
+ * Called after utrace_release_task has 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 by release_task. After this, target->utrace must be cleared.
+ */
+void
+utrace_release_task(struct task_struct *target)
+{
+ struct utrace *utrace;
+ struct utrace_attached_engine *engine, *next;
+ const struct utrace_engine_ops *ops;
+
+ task_lock(target);
+ utrace = target->utrace;
+ rcu_assign_pointer(target->utrace, NULL);
+ task_unlock(target);
+
+ if (unlikely(utrace == NULL))
+ return;
+
+restart:
+ utrace_lock(utrace);
+ 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);
+ utrace_unlock(utrace);
+ (*ops->report_reap)(engine, target);
+ call_rcu(&engine->rhead, utrace_engine_free);
+ goto restart;
+ }
+ else
+ call_rcu(&engine->rhead, utrace_engine_free);
+ }
+ utrace_unlock(utrace);
+
+ rcu_utrace_free(utrace);
+}
+
+
+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;
+
+ rcu_read_lock();
+ utrace = rcu_dereference(target->utrace);
+ smp_rmb();
+ if (unlikely(target->flags & PF_REAPED)) {
+ /*
+ * Race with utrace_release_task.
+ */
+ 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);
+
+/*
+ * 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)) {
+ 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)
+
+
+
+static u32
+remove_detached(struct task_struct *tsk, struct utrace **utracep, u32 action)
+{
+ struct utrace *utrace = tsk->utrace;
+ struct utrace_attached_engine *engine, *next;
+ unsigned long flags;
+
+ flags = 0;
+ utrace_lock(utrace);
+ 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)
+ action = remove_detached(tsk, 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.
+ */
+ if (action & UTRACE_ACTION_SINGLESTEP)
+ tracehook_enable_single_step(tsk);
+ else
+ tracehook_disable_single_step(tsk);
+#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.
+ */
+void
+utrace_report_death(struct task_struct *tsk)
+{
+ struct utrace *utrace = tsk->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.
+ */
+ action = remove_detached(tsk, &utrace, action);
+
+ check_noreap(tsk, utrace, oaction, action);
+}
+
+/*
+ * Called iff UTRACE_EVENT(VFORK_DONE) flag is set.
+ */
+void
+utrace_report_vfork_done(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;
+
+ /* 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);
+ 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);
+}
+
+
+/*
+ * 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;
+};
+
+
+// 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 (utrace->u.live.signal != &signal || 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 (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);
+ }
+
+ /*
+ * 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 value to display after "TracerPid:" in /proc/PID/status.
+ * Called without locks.
+ */
+pid_t
+utrace_tracer_pid(struct task_struct *target)
+{
+ struct utrace *utrace;
+ pid_t pid = 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->tracer_pid) {
+ pid = (*ops->tracer_pid)(engine, target);
+ if (pid)
+ break;
+ }
+ }
+ }
+ rcu_read_unlock();
+
+ return pid;
+}
+
+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;
+}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/