]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - arch/x86/kernel/ptrace.c
ptrace: cleanup arch_ptrace() on x86
[net-next-2.6.git] / arch / x86 / kernel / ptrace.c
index 2e9b55027b7e10e5a8ee31dc270ed7497439384c..45892dc4b72a37f01627725db2654591fc4dad6b 100644 (file)
@@ -2,9 +2,6 @@
 /*
  * Pentium III FXSR, SSE support
  *     Gareth Hughes <gareth@valinux.com>, May 2000
- *
- * BTS tracing
- *     Markus Metzger <markus.t.metzger@intel.com>, Dec 2007
  */
 
 #include <linux/kernel.h>
@@ -22,7 +19,6 @@
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 #include <linux/signal.h>
-#include <linux/workqueue.h>
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
 
@@ -36,7 +32,6 @@
 #include <asm/desc.h>
 #include <asm/prctl.h>
 #include <asm/proto.h>
-#include <asm/ds.h>
 #include <asm/hw_breakpoint.h>
 
 #include "tls.h"
@@ -693,7 +688,7 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
        struct perf_event_attr attr;
 
        if (!t->ptrace_bps[nr]) {
-               hw_breakpoint_init(&attr);
+               ptrace_breakpoint_init(&attr);
                /*
                 * Put stub len and type to register (reserve) an inactive but
                 * correct bp
@@ -789,342 +784,6 @@ static int ioperm_get(struct task_struct *target,
                                   0, IO_BITMAP_BYTES);
 }
 
-#ifdef CONFIG_X86_PTRACE_BTS
-/*
- * A branch trace store context.
- *
- * Contexts may only be installed by ptrace_bts_config() and only for
- * ptraced tasks.
- *
- * Contexts are destroyed when the tracee is detached from the tracer.
- * The actual destruction work requires interrupts enabled, so the
- * work is deferred and will be scheduled during __ptrace_unlink().
- *
- * Contexts hold an additional task_struct reference on the traced
- * task, as well as a reference on the tracer's mm.
- *
- * Ptrace already holds a task_struct for the duration of ptrace operations,
- * but since destruction is deferred, it may be executed after both
- * tracer and tracee exited.
- */
-struct bts_context {
-       /* The branch trace handle. */
-       struct bts_tracer       *tracer;
-
-       /* The buffer used to store the branch trace and its size. */
-       void                    *buffer;
-       unsigned int            size;
-
-       /* The mm that paid for the above buffer. */
-       struct mm_struct        *mm;
-
-       /* The task this context belongs to. */
-       struct task_struct      *task;
-
-       /* The signal to send on a bts buffer overflow. */
-       unsigned int            bts_ovfl_signal;
-
-       /* The work struct to destroy a context. */
-       struct work_struct      work;
-};
-
-static int alloc_bts_buffer(struct bts_context *context, unsigned int size)
-{
-       void *buffer = NULL;
-       int err = -ENOMEM;
-
-       err = account_locked_memory(current->mm, current->signal->rlim, size);
-       if (err < 0)
-               return err;
-
-       buffer = kzalloc(size, GFP_KERNEL);
-       if (!buffer)
-               goto out_refund;
-
-       context->buffer = buffer;
-       context->size = size;
-       context->mm = get_task_mm(current);
-
-       return 0;
-
- out_refund:
-       refund_locked_memory(current->mm, size);
-       return err;
-}
-
-static inline void free_bts_buffer(struct bts_context *context)
-{
-       if (!context->buffer)
-               return;
-
-       kfree(context->buffer);
-       context->buffer = NULL;
-
-       refund_locked_memory(context->mm, context->size);
-       context->size = 0;
-
-       mmput(context->mm);
-       context->mm = NULL;
-}
-
-static void free_bts_context_work(struct work_struct *w)
-{
-       struct bts_context *context;
-
-       context = container_of(w, struct bts_context, work);
-
-       ds_release_bts(context->tracer);
-       put_task_struct(context->task);
-       free_bts_buffer(context);
-       kfree(context);
-}
-
-static inline void free_bts_context(struct bts_context *context)
-{
-       INIT_WORK(&context->work, free_bts_context_work);
-       schedule_work(&context->work);
-}
-
-static inline struct bts_context *alloc_bts_context(struct task_struct *task)
-{
-       struct bts_context *context = kzalloc(sizeof(*context), GFP_KERNEL);
-       if (context) {
-               context->task = task;
-               task->bts = context;
-
-               get_task_struct(task);
-       }
-
-       return context;
-}
-
-static int ptrace_bts_read_record(struct task_struct *child, size_t index,
-                                 struct bts_struct __user *out)
-{
-       struct bts_context *context;
-       const struct bts_trace *trace;
-       struct bts_struct bts;
-       const unsigned char *at;
-       int error;
-
-       context = child->bts;
-       if (!context)
-               return -ESRCH;
-
-       trace = ds_read_bts(context->tracer);
-       if (!trace)
-               return -ESRCH;
-
-       at = trace->ds.top - ((index + 1) * trace->ds.size);
-       if ((void *)at < trace->ds.begin)
-               at += (trace->ds.n * trace->ds.size);
-
-       if (!trace->read)
-               return -EOPNOTSUPP;
-
-       error = trace->read(context->tracer, at, &bts);
-       if (error < 0)
-               return error;
-
-       if (copy_to_user(out, &bts, sizeof(bts)))
-               return -EFAULT;
-
-       return sizeof(bts);
-}
-
-static int ptrace_bts_drain(struct task_struct *child,
-                           long size,
-                           struct bts_struct __user *out)
-{
-       struct bts_context *context;
-       const struct bts_trace *trace;
-       const unsigned char *at;
-       int error, drained = 0;
-
-       context = child->bts;
-       if (!context)
-               return -ESRCH;
-
-       trace = ds_read_bts(context->tracer);
-       if (!trace)
-               return -ESRCH;
-
-       if (!trace->read)
-               return -EOPNOTSUPP;
-
-       if (size < (trace->ds.top - trace->ds.begin))
-               return -EIO;
-
-       for (at = trace->ds.begin; (void *)at < trace->ds.top;
-            out++, drained++, at += trace->ds.size) {
-               struct bts_struct bts;
-
-               error = trace->read(context->tracer, at, &bts);
-               if (error < 0)
-                       return error;
-
-               if (copy_to_user(out, &bts, sizeof(bts)))
-                       return -EFAULT;
-       }
-
-       memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
-
-       error = ds_reset_bts(context->tracer);
-       if (error < 0)
-               return error;
-
-       return drained;
-}
-
-static int ptrace_bts_config(struct task_struct *child,
-                            long cfg_size,
-                            const struct ptrace_bts_config __user *ucfg)
-{
-       struct bts_context *context;
-       struct ptrace_bts_config cfg;
-       unsigned int flags = 0;
-
-       if (cfg_size < sizeof(cfg))
-               return -EIO;
-
-       if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
-               return -EFAULT;
-
-       context = child->bts;
-       if (!context)
-               context = alloc_bts_context(child);
-       if (!context)
-               return -ENOMEM;
-
-       if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
-               if (!cfg.signal)
-                       return -EINVAL;
-
-               return -EOPNOTSUPP;
-               context->bts_ovfl_signal = cfg.signal;
-       }
-
-       ds_release_bts(context->tracer);
-       context->tracer = NULL;
-
-       if ((cfg.flags & PTRACE_BTS_O_ALLOC) && (cfg.size != context->size)) {
-               int err;
-
-               free_bts_buffer(context);
-               if (!cfg.size)
-                       return 0;
-
-               err = alloc_bts_buffer(context, cfg.size);
-               if (err < 0)
-                       return err;
-       }
-
-       if (cfg.flags & PTRACE_BTS_O_TRACE)
-               flags |= BTS_USER;
-
-       if (cfg.flags & PTRACE_BTS_O_SCHED)
-               flags |= BTS_TIMESTAMPS;
-
-       context->tracer =
-               ds_request_bts_task(child, context->buffer, context->size,
-                                   NULL, (size_t)-1, flags);
-       if (unlikely(IS_ERR(context->tracer))) {
-               int error = PTR_ERR(context->tracer);
-
-               free_bts_buffer(context);
-               context->tracer = NULL;
-               return error;
-       }
-
-       return sizeof(cfg);
-}
-
-static int ptrace_bts_status(struct task_struct *child,
-                            long cfg_size,
-                            struct ptrace_bts_config __user *ucfg)
-{
-       struct bts_context *context;
-       const struct bts_trace *trace;
-       struct ptrace_bts_config cfg;
-
-       context = child->bts;
-       if (!context)
-               return -ESRCH;
-
-       if (cfg_size < sizeof(cfg))
-               return -EIO;
-
-       trace = ds_read_bts(context->tracer);
-       if (!trace)
-               return -ESRCH;
-
-       memset(&cfg, 0, sizeof(cfg));
-       cfg.size        = trace->ds.end - trace->ds.begin;
-       cfg.signal      = context->bts_ovfl_signal;
-       cfg.bts_size    = sizeof(struct bts_struct);
-
-       if (cfg.signal)
-               cfg.flags |= PTRACE_BTS_O_SIGNAL;
-
-       if (trace->ds.flags & BTS_USER)
-               cfg.flags |= PTRACE_BTS_O_TRACE;
-
-       if (trace->ds.flags & BTS_TIMESTAMPS)
-               cfg.flags |= PTRACE_BTS_O_SCHED;
-
-       if (copy_to_user(ucfg, &cfg, sizeof(cfg)))
-               return -EFAULT;
-
-       return sizeof(cfg);
-}
-
-static int ptrace_bts_clear(struct task_struct *child)
-{
-       struct bts_context *context;
-       const struct bts_trace *trace;
-
-       context = child->bts;
-       if (!context)
-               return -ESRCH;
-
-       trace = ds_read_bts(context->tracer);
-       if (!trace)
-               return -ESRCH;
-
-       memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
-
-       return ds_reset_bts(context->tracer);
-}
-
-static int ptrace_bts_size(struct task_struct *child)
-{
-       struct bts_context *context;
-       const struct bts_trace *trace;
-
-       context = child->bts;
-       if (!context)
-               return -ESRCH;
-
-       trace = ds_read_bts(context->tracer);
-       if (!trace)
-               return -ESRCH;
-
-       return (trace->ds.top - trace->ds.begin) / trace->ds.size;
-}
-
-/*
- * Called from __ptrace_unlink() after the child has been moved back
- * to its original parent.
- */
-void ptrace_bts_untrace(struct task_struct *child)
-{
-       if (unlikely(child->bts)) {
-               free_bts_context(child->bts);
-               child->bts = NULL;
-       }
-}
-#endif /* CONFIG_X86_PTRACE_BTS */
-
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -1142,7 +801,8 @@ void ptrace_disable(struct task_struct *child)
 static const struct user_regset_view user_x86_32_view; /* Initialized below. */
 #endif
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+                unsigned long addr, unsigned long data)
 {
        int ret;
        unsigned long __user *datap = (unsigned long __user *)data;
@@ -1153,8 +813,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                unsigned long tmp;
 
                ret = -EIO;
-               if ((addr & (sizeof(data) - 1)) || addr < 0 ||
-                   addr >= sizeof(struct user))
+               if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
                        break;
 
                tmp = 0;  /* Default return condition */
@@ -1171,8 +830,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
        case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
                ret = -EIO;
-               if ((addr & (sizeof(data) - 1)) || addr < 0 ||
-                   addr >= sizeof(struct user))
+               if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
                        break;
 
                if (addr < sizeof(struct user_regs_struct))
@@ -1229,17 +887,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
        case PTRACE_GET_THREAD_AREA:
-               if (addr < 0)
+               if ((int) addr < 0)
                        return -EIO;
                ret = do_get_thread_area(child, addr,
-                                        (struct user_desc __user *) data);
+                                       (struct user_desc __user *)data);
                break;
 
        case PTRACE_SET_THREAD_AREA:
-               if (addr < 0)
+               if ((int) addr < 0)
                        return -EIO;
                ret = do_set_thread_area(child, addr,
-                                        (struct user_desc __user *) data, 0);
+                                       (struct user_desc __user *)data, 0);
                break;
 #endif
 
@@ -1252,39 +910,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                break;
 #endif
 
-       /*
-        * These bits need more cooking - not enabled yet:
-        */
-#ifdef CONFIG_X86_PTRACE_BTS
-       case PTRACE_BTS_CONFIG:
-               ret = ptrace_bts_config
-                       (child, data, (struct ptrace_bts_config __user *)addr);
-               break;
-
-       case PTRACE_BTS_STATUS:
-               ret = ptrace_bts_status
-                       (child, data, (struct ptrace_bts_config __user *)addr);
-               break;
-
-       case PTRACE_BTS_SIZE:
-               ret = ptrace_bts_size(child);
-               break;
-
-       case PTRACE_BTS_GET:
-               ret = ptrace_bts_read_record
-                       (child, data, (struct bts_struct __user *) addr);
-               break;
-
-       case PTRACE_BTS_CLEAR:
-               ret = ptrace_bts_clear(child);
-               break;
-
-       case PTRACE_BTS_DRAIN:
-               ret = ptrace_bts_drain
-                       (child, data, (struct bts_struct __user *) addr);
-               break;
-#endif /* CONFIG_X86_PTRACE_BTS */
-
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
@@ -1544,14 +1169,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
        case PTRACE_GET_THREAD_AREA:
        case PTRACE_SET_THREAD_AREA:
-#ifdef CONFIG_X86_PTRACE_BTS
-       case PTRACE_BTS_CONFIG:
-       case PTRACE_BTS_STATUS:
-       case PTRACE_BTS_SIZE:
-       case PTRACE_BTS_GET:
-       case PTRACE_BTS_CLEAR:
-       case PTRACE_BTS_DRAIN:
-#endif /* CONFIG_X86_PTRACE_BTS */
                return arch_ptrace(child, request, addr, data);
 
        default: