Kill context->ev_array[]. Add the new members to struct ptrace_context:
->ev_mesg: for task_struct->ptrace_message ->ev_code: for task_struct->exit_code ->ev_name: this is unique identifier for ptrace_resume(). We don't actually need both ev_code and ev_name, but ev_name makes things a bit clearer, at least for now. In particular, we can detect jctl stops because every other stop event has ev_name != 0. So, if a callback wants to stop it does context->ev_name = PTRACE_EVENT_XXX; context->ev_code = (PTRACE_EVENT_XXX << 8) | SIGTRAP; we need a helper, and we can move "(... << 8) | SIGTRAP" into ptrace_notify_stop(). The patch also adds 3 new events which are not visible to the user-mode: PTRACE_EVENT_SYSCALL PTRACE_EVENT_SIGTRAP PTRACE_EVENT_SIGNAL The last 2 are not strictly needed, just for consistency. Add the new helper, ev_pending(context) which just checks ->ev_name != 0, ptrace_resume() sets context->ev_name == 0. With this patch ptrace_resume(data) ignores "data" and doesn't implement the stacked events, see the next patches. --- kernel/ptrace.c | 181 ++++++++++++++++---------------------------------------- 1 file changed, 54 insertions(+), 127 deletions(-) --- PU/kernel/ptrace.c~53_KILL_EV_ARRAY 2009-10-01 19:35:49.000000000 +0200 +++ PU/kernel/ptrace.c 2009-10-01 21:53:01.000000000 +0200 @@ -24,57 +24,25 @@ #include <linux/syscalls.h> #include <linux/uaccess.h> -typedef void (*resume_func_t)(struct utrace_engine *, - struct task_struct*, long); - -struct ptrace_event { - int ev_code; - unsigned long ev_message; - resume_func_t ev_resume; - - int ev_options; -}; - struct ptrace_context { int options; siginfo_t *siginfo; - struct ptrace_event ev_array[2]; - unsigned int ev_first, ev_last; + int ev_name; + int ev_code; + unsigned long ev_mesg; enum utrace_resume_action resume; }; -static inline bool ev_empty(struct ptrace_context *context) -{ - return context->ev_first == context->ev_last; -} - -static inline struct ptrace_event *__ev_at(struct ptrace_context *context, - unsigned int idx) -{ - return context->ev_array + (idx % ARRAY_SIZE(context->ev_array)); -} - -static inline struct ptrace_event *ev_current(struct ptrace_context *context) -{ - WARN_ON(ev_empty(context)); - return __ev_at(context, context->ev_first); -} - -static inline struct ptrace_event *ev_pop(struct ptrace_context *context) -{ - WARN_ON(ev_empty(context)); - return __ev_at(context, context->ev_first++); -} +#define PTRACE_EVENT_SYSCALL 100 +#define PTRACE_EVENT_SIGTRAP 101 +#define PTRACE_EVENT_SIGNAL 102 -static inline struct ptrace_event *ev_push(struct ptrace_context *context) +static inline bool ev_pending(struct ptrace_context *context) { - struct ptrace_event *ev = __ev_at(context, context->ev_last++); - WARN_ON(context->ev_last - context->ev_first > ARRAY_SIZE(context->ev_array)); - memset(ev, 0, sizeof(*ev)); - return ev; + return context->ev_name != 0; } static inline struct ptrace_context * @@ -144,11 +112,12 @@ static u32 ptrace_report_exit(enum utrac long orig_code, long *code) { struct ptrace_context *context = ptrace_context(engine); - struct ptrace_event *ev; - ev = ev_push(context); - ev->ev_message = *code; - ev->ev_code = (PTRACE_EVENT_EXIT << 8) | SIGTRAP; + WARN_ON(ev_pending(context)); + + context->ev_name = PTRACE_EVENT_EXIT; + context->ev_code = (PTRACE_EVENT_EXIT << 8) | SIGTRAP; + context->ev_mesg = *code; return UTRACE_STOP; } @@ -193,7 +162,7 @@ static u32 ptrace_report_clone(enum utra struct ptrace_context *context = ptrace_context(engine); int event, ret = UTRACE_RESUME; - WARN_ON(!ev_empty(context)); + WARN_ON(ev_pending(context)); // XXX: WRONG!!! if (clone_flags & CLONE_UNTRACED) @@ -219,21 +188,16 @@ static u32 ptrace_report_clone(enum utra // XXX: child->pid is wrong! use tracer's pid_ns if (event) { - struct ptrace_event *ev = ev_push(context); - - ev->ev_message = child->pid; - ev->ev_code = (event << 8) | SIGTRAP; + context->ev_name = event; + context->ev_code = (event << 8) | SIGTRAP; + context->ev_mesg = child->pid; ret = UTRACE_STOP; - } - - if ((clone_flags & CLONE_VFORK) && - (context->options & PTRACE_O_TRACEVFORKDONE)) { - struct ptrace_event *ev = ev_push(context); - - ev->ev_message = child->pid; - ev->ev_options = PTRACE_O_TRACEVFORKDONE; - ev->ev_code = (PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP; + } else if ((clone_flags & CLONE_VFORK) && + (context->options & PTRACE_O_TRACEVFORKDONE)) { + context->ev_name = PTRACE_EVENT_VFORK_DONE; + context->ev_code = (PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP; + context->ev_mesg = child->pid; ret = UTRACE_STOP; } @@ -253,26 +217,18 @@ static void ptrace_resume_syscall(struct } } -#define PTRACE_O_TRACE_SYSCALL 0x100 - -static void push_syscall_event(struct ptrace_context *context) -{ - struct ptrace_event *ev = ev_push(context); - - BUILD_BUG_ON(PTRACE_O_TRACE_SYSCALL & PTRACE_O_MASK); - - ev->ev_options = PTRACE_O_TRACE_SYSCALL; - ev->ev_resume = ptrace_resume_syscall; - ev->ev_code = (context->options & PTRACE_O_TRACESYSGOOD) ? - (SIGTRAP | 0x80) : SIGTRAP; -} - static u32 ptrace_report_syscall_entry(u32 action, struct utrace_engine *engine, struct task_struct *task, struct pt_regs *regs) { - push_syscall_event(ptrace_context(engine)); + struct ptrace_context *context = ptrace_context(engine); + + WARN_ON(ev_pending(context)); + + context->ev_name = PTRACE_EVENT_SYSCALL; + context->ev_code = (context->options & PTRACE_O_TRACESYSGOOD) ? + (SIGTRAP | 0x80) : SIGTRAP; return UTRACE_SYSCALL_RUN | UTRACE_STOP; } @@ -281,19 +237,15 @@ static u32 ptrace_report_syscall_exit(en struct task_struct *task, struct pt_regs *regs) { - push_syscall_event(ptrace_context(engine)); - return UTRACE_STOP; -} - -static void ptrace_resume_ck_syscall(struct utrace_engine *engine, - struct task_struct *tracee, long data) -{ struct ptrace_context *context = ptrace_context(engine); - if (context->options & PTRACE_O_TRACE_SYSCALL) { - if (ev_empty(context)) - push_syscall_event(context); - } + if (ev_pending(context)) + return UTRACE_STOP; + + context->ev_name = PTRACE_EVENT_SYSCALL; + context->ev_code = (context->options & PTRACE_O_TRACESYSGOOD) ? + (SIGTRAP | 0x80) : SIGTRAP; + return UTRACE_STOP; } static u32 ptrace_report_exec(enum utrace_resume_action action, @@ -304,7 +256,8 @@ static u32 ptrace_report_exec(enum utrac struct pt_regs *regs) { struct ptrace_context *context = ptrace_context(engine); - struct ptrace_event *ev; + + WARN_ON(ev_pending(context)); if (!(context->options & PTRACE_O_TRACEEXEC)) { /* @@ -314,9 +267,8 @@ static u32 ptrace_report_exec(enum utrac return UTRACE_RESUME; } - ev = ev_push(context); - ev->ev_resume = ptrace_resume_ck_syscall; - ev->ev_code = (PTRACE_EVENT_EXEC << 8) | SIGTRAP; + context->ev_name = PTRACE_EVENT_EXEC; + context->ev_code = (PTRACE_EVENT_EXEC << 8) | SIGTRAP; return UTRACE_STOP; } @@ -351,10 +303,9 @@ static u32 ptrace_report_signal(u32 acti { struct ptrace_context *context = ptrace_context(engine); enum utrace_resume_action resume = context->resume; - struct ptrace_event *ev; - if (!ev_empty(context)) { - WARN_ON(!ev_current(context)->ev_code && !fatal_signal_pending(task)); + if (ev_pending(context)) { + WARN_ON(!context->ev_code && !fatal_signal_pending(task)); action = utrace_signal_action(action); WARN_ON(action != UTRACE_SIGNAL_REPORT); return action | UTRACE_STOP; @@ -366,8 +317,8 @@ static u32 ptrace_report_signal(u32 acti if (WARN_ON(context->siginfo)) context->siginfo = NULL; - ev = ev_push(context); - ev->ev_code = SIGTRAP; + context->ev_name = PTRACE_EVENT_SIGTRAP; + context->ev_code = SIGTRAP; return UTRACE_STOP | UTRACE_SIGNAL_IGN; } @@ -403,9 +354,8 @@ static u32 ptrace_report_signal(u32 acti // will clear context->siginfo utrace_control(task, engine, UTRACE_INTERRUPT); - ev = ev_push(context); - ev->ev_resume = ptrace_resume_signal; - ev->ev_code = info->si_signo; + context->ev_name = PTRACE_EVENT_SIGNAL; + context->ev_code = info->si_signo; return UTRACE_STOP | UTRACE_SIGNAL_IGN; } @@ -418,8 +368,8 @@ static u32 ptrace_report_quiesce(u32 act { struct ptrace_context *context = ptrace_context(engine); - if (!ev_empty(context)) { - WARN_ON(!ev_current(context)->ev_code && !fatal_signal_pending(task) && !(task->flags & PF_EXITING)); + if (ev_pending(context)) { + WARN_ON(!context->ev_code && !fatal_signal_pending(task) && !(task->flags & PF_EXITING)); return UTRACE_STOP; } @@ -886,14 +836,12 @@ static int ptrace_setsiginfo(struct utra static void do_ptrace_notify_stop(struct ptrace_context *context, struct task_struct *tracee) { - struct ptrace_event *ev = ev_current(context); - - tracee->ptrace_message = ev->ev_message; - tracee->exit_code = ev->ev_code; + tracee->ptrace_message = context->ev_mesg; + tracee->exit_code = context->ev_code; // XXX: for debug only - WARN_ON(ev->ev_code == 0); - ev->ev_code = 0; + WARN_ON(!context->ev_code); + context->ev_code = 0; // XXX: !!!!!!!! UNSAFE when called by tracer !!!!!!!!!!!!! read_lock(&tasklist_lock); @@ -913,7 +861,7 @@ void ptrace_notify_stop(struct task_stru } context = ptrace_context(engine); - if (WARN_ON(ev_empty(context))) + if (WARN_ON(!ev_pending(context))) return; do_ptrace_notify_stop(context, tracee); } @@ -943,28 +891,7 @@ static void do_ptrace_resume(struct utra { struct ptrace_context *context = ptrace_context(engine); - if (request == PTRACE_SYSCALL) - context->options |= PTRACE_O_TRACE_SYSCALL; - else - context->options &= ~PTRACE_O_TRACE_SYSCALL; - - if (!ev_empty(context)) { - struct ptrace_event *ev = ev_pop(context); - - WARN_ON(ev->ev_code); // XXX: debug - if (ev->ev_resume) - ev->ev_resume(engine, tracee, data); - - while (!ev_empty(context)) { - int ev_o = ev_current(context)->ev_options; - if (!ev_o || (ev_o & context->options)) { - do_ptrace_notify_stop(context, tracee); - return; - } - ev_pop(context); - } - } - + context->ev_name = 0; context->resume = action; ptrace_wake_up(engine, tracee, action); }