* [PATCH -mm 10/43] powerpc user_regset fpregs
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
@ 2007-12-20 11:57 ` Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 11/43] powerpc user_regset altivec Roland McGrath
` (14 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This implements user_regset-style accessors for the powerpc FPU data,
and rewrites the existing ptrace code in terms of those calls.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 37 +++++++++++++++++++++++++++++++------
1 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 8b056d2..f1ce646 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -21,6 +21,7 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
+#include <linux/regset.h>
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
@@ -103,24 +104,48 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
}
+static int fpr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ flush_fp_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
+ offsetof(struct thread_struct, fpr[32]));
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fpr, 0, -1);
+}
+
+static int fpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ flush_fp_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
+ offsetof(struct thread_struct, fpr[32]));
+
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fpr, 0, -1);
+}
+
static int get_fpregs(void __user *data, struct task_struct *task,
int has_fpscr)
{
unsigned int count = has_fpscr ? 33 : 32;
-
- if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
+ if (!access_ok(VERIFY_WRITE, data, count * sizeof(double)))
return -EFAULT;
- return 0;
+ return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data);
}
static int set_fpregs(void __user *data, struct task_struct *task,
int has_fpscr)
{
unsigned int count = has_fpscr ? 33 : 32;
-
- if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
+ if (!access_ok(VERIFY_READ, data, count * sizeof(double)))
return -EFAULT;
- return 0;
+ return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data);
}
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 11/43] powerpc user_regset altivec
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
2007-12-20 11:57 ` [PATCH -mm 10/43] powerpc user_regset fpregs Roland McGrath
@ 2007-12-20 11:57 ` Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 12/43] powerpc user_regset spe Roland McGrath
` (13 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This implements user_regset-style accessors for the powerpc Altivec data,
and rewrites the existing ptrace code in terms of those calls.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 112 +++++++++++++++++++++++++++++-------------
1 files changed, 78 insertions(+), 34 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index f1ce646..7cdf35a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/regset.h>
+#include <linux/elf.h>
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
@@ -163,30 +164,87 @@ static int set_fpregs(void __user *data, struct task_struct *task,
* (combined (32- and 64-bit) gdb.
*/
+static int vr_active(struct task_struct *target,
+ const struct user_regset *regset)
+{
+ flush_altivec_to_thread(target);
+ return target->thread.used_vr ? regset->n : 0;
+}
+
+static int vr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_altivec_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
+ offsetof(struct thread_struct, vr[32]));
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.vr, 0,
+ 33 * sizeof(vector128));
+ if (!ret) {
+ /*
+ * Copy out only the low-order word of vrsave.
+ */
+ union {
+ elf_vrreg_t reg;
+ u32 word;
+ } vrsave;
+ memset(&vrsave, 0, sizeof(vrsave));
+ vrsave.word = target->thread.vrsave;
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 33 * sizeof(vector128), -1);
+ }
+
+ return ret;
+}
+
+static int vr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_altivec_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
+ offsetof(struct thread_struct, vr[32]));
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.vr, 0, 33 * sizeof(vector128));
+ if (!ret && count > 0) {
+ /*
+ * We use only the first word of vrsave.
+ */
+ union {
+ elf_vrreg_t reg;
+ u32 word;
+ } vrsave;
+ memset(&vrsave, 0, sizeof(vrsave));
+ vrsave.word = target->thread.vrsave;
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 33 * sizeof(vector128), -1);
+ if (!ret)
+ target->thread.vrsave = vrsave.word;
+ }
+
+ return ret;
+}
+
/*
* Get contents of AltiVec register state in task TASK
*/
static int get_vrregs(unsigned long __user *data, struct task_struct *task)
{
- unsigned long regsize;
-
- /* copy AltiVec registers VR[0] .. VR[31] */
- regsize = 32 * sizeof(vector128);
- if (copy_to_user(data, task->thread.vr, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VSCR */
- regsize = 1 * sizeof(vector128);
- if (copy_to_user(data, &task->thread.vscr, regsize))
+ if (!access_ok(VERIFY_WRITE, data,
+ 33 * sizeof(vector128) + sizeof(u32)))
return -EFAULT;
- data += (regsize / sizeof(unsigned long));
- /* copy VRSAVE */
- if (put_user(task->thread.vrsave, (u32 __user *)data))
- return -EFAULT;
-
- return 0;
+ return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
+ NULL, data);
}
/*
@@ -194,25 +252,11 @@ static int get_vrregs(unsigned long __user *data, struct task_struct *task)
*/
static int set_vrregs(struct task_struct *task, unsigned long __user *data)
{
- unsigned long regsize;
-
- /* copy AltiVec registers VR[0] .. VR[31] */
- regsize = 32 * sizeof(vector128);
- if (copy_from_user(task->thread.vr, data, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VSCR */
- regsize = 1 * sizeof(vector128);
- if (copy_from_user(&task->thread.vscr, data, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VRSAVE */
- if (get_user(task->thread.vrsave, (u32 __user *)data))
+ if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32)))
return -EFAULT;
- return 0;
+ return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
+ NULL, data);
}
#endif /* CONFIG_ALTIVEC */
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 12/43] powerpc user_regset spe
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
2007-12-20 11:57 ` [PATCH -mm 10/43] powerpc user_regset fpregs Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 11/43] powerpc user_regset altivec Roland McGrath
@ 2007-12-20 11:57 ` Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 13/43] powerpc ptrace special regs Roland McGrath
` (12 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This implements user_regset-style accessors for the powerpc SPE data,
and rewrites the existing ptrace code in terms of those calls.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 90 ++++++++++++++++++++++++++---------------
1 files changed, 57 insertions(+), 33 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 7cdf35a..8c25b00 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -272,55 +272,79 @@ static int set_vrregs(struct task_struct *task, unsigned long __user *data)
* }
*/
-/*
- * Get contents of SPE register state in task TASK.
- */
-static int get_evrregs(unsigned long *data, struct task_struct *task)
+static int evr_active(struct task_struct *target,
+ const struct user_regset *regset)
{
- int i;
+ flush_spe_to_thread(target);
+ return target->thread.used_spe ? regset->n : 0;
+}
- if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
- return -EFAULT;
+static int evr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
- /* copy SPEFSCR */
- if (__put_user(task->thread.spefscr, &data[34]))
- return -EFAULT;
+ flush_spe_to_thread(target);
- /* copy SPE registers EVR[0] .. EVR[31] */
- for (i = 0; i < 32; i++, data++)
- if (__put_user(task->thread.evr[i], data))
- return -EFAULT;
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.evr,
+ 0, sizeof(target->thread.evr));
- /* copy ACC */
- if (__put_user64(task->thread.acc, (unsigned long long *)data))
- return -EFAULT;
+ BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
+ offsetof(struct thread_struct, spefscr));
- return 0;
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.acc,
+ sizeof(target->thread.evr), -1);
+
+ return ret;
+}
+
+static int evr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_spe_to_thread(target);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.evr,
+ 0, sizeof(target->thread.evr));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
+ offsetof(struct thread_struct, spefscr));
+
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.acc,
+ sizeof(target->thread.evr), -1);
+
+ return ret;
}
/*
- * Write contents of SPE register state into task TASK.
+ * Get contents of SPE register state in task TASK.
*/
-static int set_evrregs(struct task_struct *task, unsigned long *data)
+static int get_evrregs(unsigned long __user *data, struct task_struct *task)
{
- int i;
-
- if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
+ if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32)))
return -EFAULT;
- /* copy SPEFSCR */
- if (__get_user(task->thread.spefscr, &data[34]))
- return -EFAULT;
+ return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data);
+}
- /* copy SPE registers EVR[0] .. EVR[31] */
- for (i = 0; i < 32; i++, data++)
- if (__get_user(task->thread.evr[i], data))
- return -EFAULT;
- /* copy ACC */
- if (__get_user64(task->thread.acc, (unsigned long long*)data))
+/*
+ * Write contents of SPE register state into task TASK.
+ */
+static int set_evrregs(struct task_struct *task, unsigned long *data)
+{
+ if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32)))
return -EFAULT;
- return 0;
+ return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data);
}
#endif /* CONFIG_SPE */
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 13/43] powerpc ptrace special regs
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (2 preceding siblings ...)
2007-12-20 11:57 ` [PATCH -mm 12/43] powerpc user_regset spe Roland McGrath
@ 2007-12-20 11:57 ` Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 14/43] powerpc user_regset gpr Roland McGrath
` (11 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This isolates the ptrace code for the special-case registers msr and trap
from the ptrace-layout dispatch code. This should inline away completely.
It cleanly separates the low-level machine magic that has to be done for
deep reasons, from the superficial details of the ptrace interface.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 45 ++++++++++++++++++++++++++++--------------
1 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 8c25b00..4edc118 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -60,20 +60,38 @@
#define PT_MAX_PUT_REG PT_CCR
#endif
+static unsigned long get_user_msr(struct task_struct *task)
+{
+ return task->thread.regs->msr | task->thread.fpexc_mode;
+}
+
+static int set_user_msr(struct task_struct *task, unsigned long msr)
+{
+ task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
+ task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
+ return 0;
+}
+
+/*
+ * We prevent mucking around with the reserved area of trap
+ * which are used internally by the kernel.
+ */
+static int set_user_trap(struct task_struct *task, unsigned long trap)
+{
+ task->thread.regs->trap = trap & 0xfff0;
+ return 0;
+}
+
/*
* Get contents of register REGNO in task TASK.
*/
unsigned long ptrace_get_reg(struct task_struct *task, int regno)
{
- unsigned long tmp = 0;
-
if (task->thread.regs == NULL)
return -EIO;
- if (regno == PT_MSR) {
- tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
- return tmp | task->thread.fpexc_mode;
- }
+ if (regno == PT_MSR)
+ return get_user_msr(task);
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
return ((unsigned long *)task->thread.regs)[regno];
@@ -89,15 +107,12 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
if (task->thread.regs == NULL)
return -EIO;
- if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
- if (regno == PT_MSR)
- data = (data & MSR_DEBUGCHANGE)
- | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
- /* We prevent mucking around with the reserved area of trap
- * which are used internally by the kernel
- */
- if (regno == PT_TRAP)
- data &= 0xfff0;
+ if (regno == PT_MSR)
+ return set_user_msr(task, data);
+ if (regno == PT_TRAP)
+ return set_user_trap(task, data);
+
+ if (regno <= PT_MAX_PUT_REG) {
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 14/43] powerpc user_regset gpr
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (3 preceding siblings ...)
2007-12-20 11:57 ` [PATCH -mm 13/43] powerpc ptrace special regs Roland McGrath
@ 2007-12-20 11:57 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 15/43] powerpc user_regset_view Roland McGrath
` (10 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:57 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This implements user_regset-style accessors for the powerpc general registers.
In the future these functions will be the only place that needs to understand
the user_regset layout (core dump format) and how it maps to the internal
representation of user thread state.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 91 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 4edc118..e493fc0 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -119,6 +119,97 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
return -EIO;
}
+static int gpr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ target->thread.regs,
+ 0, offsetof(struct pt_regs, msr));
+ if (!ret) {
+ unsigned long msr = get_user_msr(target);
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
+ offsetof(struct pt_regs, msr),
+ offsetof(struct pt_regs, msr) +
+ sizeof(msr));
+ }
+
+ BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+ offsetof(struct pt_regs, msr) + sizeof(long));
+
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.regs->orig_gpr3,
+ offsetof(struct pt_regs, orig_gpr3),
+ sizeof(struct pt_regs));
+ if (!ret)
+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ sizeof(struct pt_regs), -1);
+
+ return ret;
+}
+
+static int gpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ unsigned long reg;
+ int ret;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ target->thread.regs,
+ 0, PT_MSR * sizeof(reg));
+
+ if (!ret && count > 0) {
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
+ PT_MSR * sizeof(reg),
+ (PT_MSR + 1) * sizeof(reg));
+ if (!ret)
+ ret = set_user_msr(target, reg);
+ }
+
+ BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+ offsetof(struct pt_regs, msr) + sizeof(long));
+
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.regs->orig_gpr3,
+ PT_ORIG_R3 * sizeof(reg),
+ (PT_MAX_PUT_REG + 1) * sizeof(reg));
+
+ if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
+ ret = user_regset_copyin_ignore(
+ &pos, &count, &kbuf, &ubuf,
+ (PT_MAX_PUT_REG + 1) * sizeof(reg),
+ PT_TRAP * sizeof(reg));
+
+ if (!ret && count > 0) {
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
+ PT_TRAP * sizeof(reg),
+ (PT_TRAP + 1) * sizeof(reg));
+ if (!ret)
+ ret = set_user_trap(target, reg);
+ }
+
+ if (!ret)
+ ret = user_regset_copyin_ignore(
+ &pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
+
+ return ret;
+}
static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 15/43] powerpc user_regset_view
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (4 preceding siblings ...)
2007-12-20 11:57 ` [PATCH -mm 14/43] powerpc user_regset gpr Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 16/43] powerpc user_regset compat Roland McGrath
` (9 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This provides the task_user_regset_view entry point and support for all the
native-mode (64 on CONFIG_PPC64, 32 on CONFIG_PPC32) thread register state.
This will enable generic machine-independent code to access user-mode
threads' registers for debugging and dumping.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/Makefile | 2 +
arch/powerpc/kernel/ptrace.c | 52 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index ca51f0c..615ed96 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -2,6 +2,8 @@
# Makefile for the linux kernel.
#
+CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
+
ifeq ($(CONFIG_PPC64),y)
EXTRA_CFLAGS += -mno-minimal-toc
endif
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index e493fc0..b32ac5f 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -455,6 +455,58 @@ static int set_evrregs(struct task_struct *task, unsigned long *data)
#endif /* CONFIG_SPE */
+/*
+ * These are our native regset flavors.
+ */
+enum powerpc_regset {
+ REGSET_GPR,
+ REGSET_FPR,
+#ifdef CONFIG_ALTIVEC
+ REGSET_VMX,
+#endif
+#ifdef CONFIG_SPE
+ REGSET_SPE,
+#endif
+};
+
+static const struct user_regset native_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+ .size = sizeof(long), .align = sizeof(long),
+ .get = gpr_get, .set = gpr_set
+ },
+ [REGSET_FPR] = {
+ .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = fpr_get, .set = fpr_set
+ },
+#ifdef CONFIG_ALTIVEC
+ [REGSET_VMX] = {
+ .core_note_type = NT_PPC_VMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .active = vr_active, .get = vr_get, .set = vr_set
+ },
+#endif
+#ifdef CONFIG_SPE
+ [REGSET_SPE] = {
+ .n = 35,
+ .size = sizeof(u32), .align = sizeof(u32),
+ .active = evr_active, .get = evr_get, .set = evr_set
+ },
+#endif
+};
+
+static const struct user_regset_view user_ppc_native_view = {
+ .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
+ .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &user_ppc_native_view;
+}
+
+
void user_enable_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 16/43] powerpc user_regset compat
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (5 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 15/43] powerpc user_regset_view Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2008-01-07 5:40 ` [PATCH update " Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 17/43] powerpc CORE_DUMP_USE_REGSET Roland McGrath
` (8 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This extends task_user_regset_view CONFIG_PPC64 with support for the 32-bit
view of register state, compatible with what a CONFIG_PPC32 kernel provides.
This will enable generic machine-independent code to access user-mode
threads' registers for debugging and dumping.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 158 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 158 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index b32ac5f..e961e10 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -501,8 +501,166 @@ static const struct user_regset_view user_ppc_native_view = {
.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
};
+#ifdef CONFIG_PPC64
+#include <linux/compat.h>
+
+static int gpr32_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ const unsigned long *regs = &target->thread.regs->gpr[0];
+ compat_ulong_t *k = kbuf;
+ compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_MSR; --count)
+ *k++ = regs[pos++];
+ else
+ for (; count > 0 && pos < PT_MSR; --count)
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
+ return -EFAULT;
+
+ if (count > 0 && pos == PT_MSR) {
+ reg = get_user_msr(target);
+ if (kbuf)
+ *k++ = reg;
+ else if (__put_user(reg, u++))
+ return -EFAULT;
+ ++pos;
+ --count;
+ }
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
+ *k++ = regs[pos++];
+ else
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
+ return -EFAULT;
+
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ PT_REGS_COUNT * sizeof(reg), -1);
+}
+
+static int gpr32_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ unsigned long *regs = &target->thread.regs->gpr[0];
+ const compat_ulong_t *k = kbuf;
+ const compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_MSR; --count)
+ regs[pos++] = *k++;
+ else
+ for (; count > 0 && pos < PT_MSR; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs[pos++] = reg;
+ }
+
+
+ if (count > 0 && pos == PT_MSR) {
+ if (kbuf)
+ reg = *k++;
+ else if (__get_user(reg, u++))
+ return -EFAULT;
+ set_user_msr(target, reg);
+ ++pos;
+ --count;
+ }
+
+ if (kbuf)
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
+ regs[pos++] = *k++;
+ else
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs[pos++] = reg;
+ }
+
+ if (count > 0 && pos == PT_TRAP) {
+ if (kbuf)
+ reg = *k++;
+ else if (__get_user(reg, u++))
+ return -EFAULT;
+ set_user_trap(target, reg);
+ ++pos;
+ --count;
+ }
+
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
+}
+
+/*
+ * These are the regset flavors matching the CONFIG_PPC32 native set.
+ */
+static const struct user_regset compat_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+ .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
+ .get = gpr32_get, .set = gpr32_set
+ },
+ [REGSET_FPR] = {
+ .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = fpr_get, .set = fpr_set
+ },
+#ifdef CONFIG_ALTIVEC
+ [REGSET_VMX] = {
+ .core_note_type = NT_PPC_VMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .active = vr_active, .get = vr_get, .set = vr_set
+ },
+#endif
+#ifdef CONFIG_SPE
+ [REGSET_SPE] = {
+ .n = 35,
+ .size = sizeof(u32), .align = sizeof(u32),
+ .active = evr_active, .get = evr_get, .set = evr_set
+ },
+#endif
+};
+
+static const struct user_regset_view user_ppc_compat_view = {
+ .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
+ .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
+};
+#endif /* CONFIG_PPC64 */
+
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
+#ifdef CONFIG_PPC64
+ if (test_tsk_thread_flag(task, TIF_32BIT))
+ return &user_ppc_compat_view;
+#endif
return &user_ppc_native_view;
}
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 17/43] powerpc CORE_DUMP_USE_REGSET
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (6 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 16/43] powerpc user_regset compat Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 18/43] powerpc compat_binfmt_elf Roland McGrath
` (7 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This switches powerpc to using the user_regset-based code for ELF core
dumps. The core dumps come out exactly the same either way, except that
the NT_PPC_VMX note is now omitted for any thread that never touched its
Altivec registers (thread_struct.vr_used).
Signed-off-by: Roland McGrath <roland@redhat.com>
---
include/asm-powerpc/elf.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 6bd07ef..fd9bf8b 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -167,6 +167,7 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
#define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
#define USE_ELF_CORE_DUMP
+#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE PAGE_SIZE
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 18/43] powerpc compat_binfmt_elf
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (7 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 17/43] powerpc CORE_DUMP_USE_REGSET Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-21 7:12 ` Christoph Hellwig
2007-12-20 11:58 ` [PATCH -mm 19/43] powerpc core dump cleanup Roland McGrath
` (6 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This switches the CONFIG_PPC64 support for 32-bit ELF to use the generic
fs/compat_binfmt_elf.c implementation instead of our own binfmt_elf32.c.
Since so much is the same between 32/64, there is only one macro we have to
define to make the generic support work out of the box.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/Makefile | 3 +-
arch/powerpc/kernel/binfmt_elf32.c | 69 ------------------------------------
include/asm-powerpc/elf.h | 1 +
3 files changed, 3 insertions(+), 70 deletions(-)
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 615ed96..2cbe58a 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,11 +17,12 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
init_task.o process.o systbl.o idle.o \
signal.o
obj-y += vdso32/
-obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
+obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
signal_64.o ptrace32.o \
paca.o cpu_setup_ppc970.o \
cpu_setup_pa6t.o \
firmware.o sysfs.o nvram_64.o
+obj-$(CONFIG_PPC64) += ../../../fs/compat_binfmt_elf.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
diff --git a/arch/powerpc/kernel/binfmt_elf32.c b/arch/powerpc/kernel/binfmt_elf32.c
deleted file mode 100644
index 1d45d77..0000000
--- a/arch/powerpc/kernel/binfmt_elf32.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons.
- * based on the SPARC64 version.
- * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
- *
- * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp
- * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/processor.h>
-#include <linux/module.h>
-#include <linux/compat.h>
-#include <linux/elfcore-compat.h>
-
-#undef ELF_ARCH
-#undef ELF_CLASS
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_PPC
-
-#undef elfhdr
-#undef elf_phdr
-#undef elf_note
-#undef elf_addr_t
-#define elfhdr elf32_hdr
-#define elf_phdr elf32_phdr
-#define elf_note elf32_note
-#define elf_addr_t Elf32_Off
-
-#define elf_prstatus compat_elf_prstatus
-#define elf_prpsinfo compat_elf_prpsinfo
-
-#define elf_core_copy_regs compat_elf_core_copy_regs
-static inline void compat_elf_core_copy_regs(compat_elf_gregset_t *elf_regs,
- struct pt_regs *regs)
-{
- PPC_ELF_CORE_COPY_REGS((*elf_regs), regs);
-}
-
-#define elf_core_copy_task_regs compat_elf_core_copy_task_regs
-static int compat_elf_core_copy_task_regs(struct task_struct *tsk,
- compat_elf_gregset_t *elf_regs)
-{
- struct pt_regs *regs = tsk->thread.regs;
- if (regs)
- compat_elf_core_copy_regs(elf_regs, regs);
- return 1;
-}
-
-#include <linux/time.h>
-
-#undef cputime_to_timeval
-#define cputime_to_timeval cputime_to_compat_timeval
-static __inline__ void
-cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
-{
- unsigned long jiffies = cputime_to_jiffies(cputime);
- value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
- value->tv_sec = jiffies / HZ;
-}
-
-#define init_elf_binfmt init_elf32_binfmt
-
-#include "../../../fs/binfmt_elf.c"
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index fd9bf8b..9080d85 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -165,6 +165,7 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
+#define compat_elf_check_arch(x) ((x)->e_machine == EM_PPC)
#define USE_ELF_CORE_DUMP
#define CORE_DUMP_USE_REGSET
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 19/43] powerpc core dump cleanup
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (8 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 18/43] powerpc compat_binfmt_elf Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 20/43] powerpc SPE core dump Roland McGrath
` (5 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
Remove some dead code we no longer need now that the
user_regset interfaces are doing all these jobs.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/process.c | 48 -----------------------------------------
include/asm-powerpc/elf.h | 46 ---------------------------------------
2 files changed, 0 insertions(+), 94 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index b9d8837..9c2983c 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -104,17 +104,6 @@ void enable_kernel_fp(void)
}
EXPORT_SYMBOL(enable_kernel_fp);
-int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
-{
- if (!tsk->thread.regs)
- return 0;
- flush_fp_to_thread(current);
-
- memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs));
-
- return 1;
-}
-
#ifdef CONFIG_ALTIVEC
void enable_kernel_altivec(void)
{
@@ -148,35 +137,6 @@ void flush_altivec_to_thread(struct task_struct *tsk)
preempt_enable();
}
}
-
-int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs)
-{
- /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save
- * separately, see below */
- const int nregs = ELF_NVRREG - 2;
- elf_vrreg_t *reg;
- u32 *dest;
-
- if (tsk == current)
- flush_altivec_to_thread(tsk);
-
- reg = (elf_vrreg_t *)vrregs;
-
- /* copy the 32 vr registers */
- memcpy(reg, &tsk->thread.vr[0], nregs * sizeof(*reg));
- reg += nregs;
-
- /* copy the vscr */
- memcpy(reg, &tsk->thread.vscr, sizeof(*reg));
- reg++;
-
- /* vrsave is stored in the high 32bit slot of the final 128bits */
- memset(reg, 0, sizeof(*reg));
- dest = (u32 *)reg;
- *dest = tsk->thread.vrsave;
-
- return 1;
-}
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
@@ -209,14 +169,6 @@ void flush_spe_to_thread(struct task_struct *tsk)
preempt_enable();
}
}
-
-int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs)
-{
- flush_spe_to_thread(current);
- /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */
- memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35);
- return 1;
-}
#endif /* CONFIG_SPE */
#ifndef CONFIG_SMP
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 9080d85..fe309b4 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -178,52 +178,6 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
#define ELF_ET_DYN_BASE (0x20000000)
-/*
- * Our registers are always unsigned longs, whether we're a 32 bit
- * process or 64 bit, on either a 64 bit or 32 bit kernel.
- *
- * This macro relies on elf_regs[i] having the right type to truncate to,
- * either u32 or u64. It defines the body of the elf_core_copy_regs
- * function, either the native one with elf_gregset_t elf_regs or
- * the 32-bit one with elf_gregset_t32 elf_regs.
- */
-#define PPC_ELF_CORE_COPY_REGS(elf_regs, regs) \
- int i, nregs = min(sizeof(*regs) / sizeof(unsigned long), \
- (size_t)ELF_NGREG); \
- for (i = 0; i < nregs; i++) \
- elf_regs[i] = ((unsigned long *) regs)[i]; \
- memset(&elf_regs[i], 0, (ELF_NGREG - i) * sizeof(elf_regs[0]))
-
-/* Common routine for both 32-bit and 64-bit native processes */
-static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs,
- struct pt_regs *regs)
-{
- PPC_ELF_CORE_COPY_REGS(elf_regs, regs);
-}
-#define ELF_CORE_COPY_REGS(gregs, regs) ppc_elf_core_copy_regs(gregs, regs);
-
-static inline int dump_task_regs(struct task_struct *tsk,
- elf_gregset_t *elf_regs)
-{
- struct pt_regs *regs = tsk->thread.regs;
- if (regs)
- ppc_elf_core_copy_regs(*elf_regs, regs);
-
- return 1;
-}
-#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
-
-extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
-#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
-
-typedef elf_vrregset_t elf_fpxregset_t;
-
-#ifdef CONFIG_ALTIVEC
-extern int dump_task_altivec(struct task_struct *, elf_vrregset_t *vrregs);
-#define ELF_CORE_COPY_XFPREGS(tsk, regs) dump_task_altivec(tsk, regs)
-#define ELF_CORE_XFPREG_TYPE NT_PPC_VMX
-#endif
-
#endif /* __KERNEL__ */
/* ELF_HWCAP yields a mask that user programs can use to figure out what
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 20/43] powerpc SPE core dump
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (9 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 19/43] powerpc core dump cleanup Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 21/43] powerpc ptrace user_regset Roland McGrath
` (4 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This makes the SPE register data appear in ELF core dumps,
using the new n_type value NT_PPC_SPE (0x101). This new
note type is not used by any consumers of core files yet,
but support can be added. I don't even have any hardware
with SPE capabilities, so I've never seen such a note.
But this demonstrates how simple it is to export register
information in core dumps when the user_regset style is
used for the low-level code.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 2 +-
include/linux/elf.h | 1 +
2 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index e961e10..0231e7d 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -642,7 +642,7 @@ static const struct user_regset compat_regsets[] = {
#endif
#ifdef CONFIG_SPE
[REGSET_SPE] = {
- .n = 35,
+ .core_note_type = NT_PPC_SPE, .n = 35,
.size = sizeof(u32), .align = sizeof(u32),
.active = evr_active, .get = evr_get, .set = evr_set
},
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 576e83b..ba268b2 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -355,6 +355,7 @@ typedef struct elf64_shdr {
#define NT_AUXV 6
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
/* Note header in a PT_NOTE section */
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 21/43] powerpc ptrace user_regset
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (10 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 20/43] powerpc SPE core dump Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 22/43] powerpc ptrace generic peekdata/pokedata Roland McGrath
` (3 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This replaces all the code for powerpc PTRACE_*REGS* requests with
simple calls to copy_regset_from_user and copy_regset_to_user. All
the ptrace formats are either the whole corresponding user_regset
format (core dump format) or a leading subset of it, so we can get
rid of all the remaining embedded knowledge of both those layouts
and of the internal data structures they correspond to. Only the
user_reget accessors need to implement that.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 234 +++++++++++-------------------------------
1 files changed, 59 insertions(+), 175 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 0231e7d..eb27bd9 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -237,24 +237,6 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
&target->thread.fpr, 0, -1);
}
-static int get_fpregs(void __user *data, struct task_struct *task,
- int has_fpscr)
-{
- unsigned int count = has_fpscr ? 33 : 32;
- if (!access_ok(VERIFY_WRITE, data, count * sizeof(double)))
- return -EFAULT;
- return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data);
-}
-
-static int set_fpregs(void __user *data, struct task_struct *task,
- int has_fpscr)
-{
- unsigned int count = has_fpscr ? 33 : 32;
- if (!access_ok(VERIFY_READ, data, count * sizeof(double)))
- return -EFAULT;
- return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data);
-}
-
#ifdef CONFIG_ALTIVEC
/*
@@ -339,31 +321,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
return ret;
}
-
-/*
- * Get contents of AltiVec register state in task TASK
- */
-static int get_vrregs(unsigned long __user *data, struct task_struct *task)
-{
- if (!access_ok(VERIFY_WRITE, data,
- 33 * sizeof(vector128) + sizeof(u32)))
- return -EFAULT;
-
- return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
- NULL, data);
-}
-
-/*
- * Write contents of AltiVec register state into task TASK.
- */
-static int set_vrregs(struct task_struct *task, unsigned long __user *data)
-{
- if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32)))
- return -EFAULT;
-
- return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32),
- NULL, data);
-}
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
@@ -430,28 +387,6 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
return ret;
}
-
-/*
- * Get contents of SPE register state in task TASK.
- */
-static int get_evrregs(unsigned long __user *data, struct task_struct *task)
-{
- if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32)))
- return -EFAULT;
-
- return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data);
-}
-
-/*
- * Write contents of SPE register state into task TASK.
- */
-static int set_evrregs(struct task_struct *task, unsigned long *data)
-{
- if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32)))
- return -EFAULT;
-
- return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data);
-}
#endif /* CONFIG_SPE */
@@ -732,55 +667,29 @@ void ptrace_disable(struct task_struct *child)
static long arch_ptrace_old(struct task_struct *child, long request, long addr,
long data)
{
- int ret = -EPERM;
-
- switch(request) {
- case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
- CHECK_FULL_REGS(child->thread.regs);
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
- break;
- }
-
- case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
- CHECK_FULL_REGS(child->thread.regs);
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
- break;
- }
-
- case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
- flush_fp_to_thread(child);
- ret = get_fpregs((void __user *)addr, child, 0);
- break;
- }
-
- case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
- flush_fp_to_thread(child);
- ret = set_fpregs((void __user *)addr, child, 0);
- break;
+ switch (request) {
+ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_GPR, 0, 32 * sizeof(long),
+ (void __user *) data);
+
+ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_GPR, 0, 32 * sizeof(long),
+ (const void __user *) data);
+
+ case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_FPR, 0, 32 * sizeof(double),
+ (void __user *) data);
+
+ case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_FPR, 0, 32 * sizeof(double),
+ (const void __user *) data);
}
- }
- return ret;
+ return -EPERM;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -871,85 +780,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef CONFIG_PPC64
case PTRACE_GETREGS64:
#endif
- case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
- int ui;
- if (!access_ok(VERIFY_WRITE, (void __user *)data,
- sizeof(struct pt_regs))) {
- ret = -EIO;
- break;
- }
- CHECK_FULL_REGS(child->thread.regs);
- ret = 0;
- for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
- ret |= __put_user(ptrace_get_reg(child, ui),
- (unsigned long __user *) data);
- data += sizeof(long);
- }
- break;
- }
+ case PTRACE_GETREGS: /* Get all pt_regs from the child. */
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_GPR,
+ 0, sizeof(struct pt_regs),
+ (void __user *) data);
#ifdef CONFIG_PPC64
case PTRACE_SETREGS64:
#endif
- case PTRACE_SETREGS: { /* Set all gp regs in the child. */
- unsigned long tmp;
- int ui;
- if (!access_ok(VERIFY_READ, (void __user *)data,
- sizeof(struct pt_regs))) {
- ret = -EIO;
- break;
- }
- CHECK_FULL_REGS(child->thread.regs);
- ret = 0;
- for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
- ret = __get_user(tmp, (unsigned long __user *) data);
- if (ret)
- break;
- ptrace_put_reg(child, ui, tmp);
- data += sizeof(long);
- }
- break;
- }
-
- case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
- flush_fp_to_thread(child);
- ret = get_fpregs((void __user *)data, child, 1);
- break;
- }
-
- case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
- flush_fp_to_thread(child);
- ret = set_fpregs((void __user *)data, child, 1);
- break;
- }
+ case PTRACE_SETREGS: /* Set all gp regs in the child. */
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_GPR,
+ 0, sizeof(struct pt_regs),
+ (const void __user *) data);
+
+ case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_FPR,
+ 0, sizeof(elf_fpregset_t),
+ (void __user *) data);
+
+ case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_FPR,
+ 0, sizeof(elf_fpregset_t),
+ (const void __user *) data);
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
- /* Get the child altivec register state. */
- flush_altivec_to_thread(child);
- ret = get_vrregs((unsigned long __user *)data, child);
- break;
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_VMX,
+ 0, (33 * sizeof(vector128) +
+ sizeof(u32)),
+ (void __user *) data);
case PTRACE_SETVRREGS:
- /* Set the child altivec register state. */
- flush_altivec_to_thread(child);
- ret = set_vrregs(child, (unsigned long __user *)data);
- break;
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_VMX,
+ 0, (33 * sizeof(vector128) +
+ sizeof(u32)),
+ (const void __user *) data);
#endif
#ifdef CONFIG_SPE
case PTRACE_GETEVRREGS:
/* Get the child spe register state. */
- flush_spe_to_thread(child);
- ret = get_evrregs((unsigned long __user *)data, child);
- break;
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_SPE, 0, 35 * sizeof(u32),
+ (void __user *) data);
case PTRACE_SETEVRREGS:
/* Set the child spe register state. */
- /* this is to clear the MSR_SPE bit to force a reload
- * of register state from memory */
- flush_spe_to_thread(child);
- ret = set_evrregs(child, (unsigned long __user *)data);
- break;
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_SPE, 0, 35 * sizeof(u32),
+ (const void __user *) data);
#endif
/* Old reverse args ptrace callss */
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 22/43] powerpc ptrace generic peekdata/pokedata
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (11 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 21/43] powerpc ptrace user_regset Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 23/43] powerpc compat_ptrace_request Roland McGrath
` (2 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
Now that ptrace_request handles these, we can drop some more boilerplate.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 12 ------------
1 files changed, 0 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index eb27bd9..3e228d6 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -697,12 +697,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int ret = -EPERM;
switch (request) {
- /* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA:
- ret = generic_ptrace_peekdata(child, addr, data);
- break;
-
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long index, tmp;
@@ -730,12 +724,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
- /* If I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- ret = generic_ptrace_pokedata(child, addr, data);
- break;
-
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR: {
unsigned long index;
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 23/43] powerpc compat_ptrace_request
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (12 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 22/43] powerpc ptrace generic peekdata/pokedata Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 24/43] powerpc compat_sys_ptrace Roland McGrath
2007-12-20 11:59 ` [PATCH -mm 25/43] powerpc ptrace32 user_regset Roland McGrath
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This removes some duplicated code by calling the new generic
compat_ptrace_request from powerpc's compat_sys_ptrace.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace32.c | 34 ++--------------------------------
1 files changed, 2 insertions(+), 32 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index fea6206..6612304 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -27,6 +27,7 @@
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -112,20 +113,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
goto out_tsk;
switch (request) {
- /* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned int tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp, (u32 __user *)data);
- break;
- }
-
/*
* Read 4 bytes of the other process' storage
* data is a pointer specifying where the user wants the
@@ -225,19 +212,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
break;
}
- /* If I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA: {
- unsigned int tmp;
- tmp = data;
- ret = 0;
- if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
- == sizeof(tmp))
- break;
- ret = -EIO;
- break;
- }
-
/*
* Write 4 bytes into the other process' storage
* data is the 4 bytes that the user wants written
@@ -337,10 +311,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
break;
}
- case PTRACE_GETEVENTMSG:
- ret = put_user(child->ptrace_message, (unsigned int __user *) data);
- break;
-
case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
int ui;
if (!access_ok(VERIFY_WRITE, (void __user *)data,
@@ -402,7 +372,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
break;
default:
- ret = ptrace_request(child, request, addr, data);
+ ret = compat_ptrace_request(child, request, addr, data);
break;
}
out_tsk:
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 24/43] powerpc compat_sys_ptrace
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (13 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 23/43] powerpc compat_ptrace_request Roland McGrath
@ 2007-12-20 11:58 ` Roland McGrath
2007-12-20 11:59 ` [PATCH -mm 25/43] powerpc ptrace32 user_regset Roland McGrath
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:58 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This replaces powerpc's compat_sys_ptrace with a compat_arch_ptrace and
enables the new generic definition of compat_sys_ptrace instead.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace32.c | 33 +++++----------------------------
include/asm-powerpc/ptrace.h | 2 ++
2 files changed, 7 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 6612304..0f6eea0 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -85,33 +85,13 @@ static long compat_ptrace_old(struct task_struct *child, long request,
return ret;
}
-long compat_sys_ptrace(int request, int pid, unsigned long addr,
- unsigned long data)
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
{
- struct task_struct *child;
+ unsigned long addr = caddr;
+ unsigned long data = cdata;
int ret;
- lock_kernel();
- if (request == PTRACE_TRACEME) {
- ret = ptrace_traceme();
- goto out;
- }
-
- child = ptrace_get_task_struct(pid);
- if (IS_ERR(child)) {
- ret = PTR_ERR(child);
- goto out;
- }
-
- if (request == PTRACE_ATTACH) {
- ret = ptrace_attach(child);
- goto out_tsk;
- }
-
- ret = ptrace_check_attach(child, request == PTRACE_KILL);
- if (ret < 0)
- goto out_tsk;
-
switch (request) {
/*
* Read 4 bytes of the other process' storage
@@ -375,9 +355,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
ret = compat_ptrace_request(child, request, addr, data);
break;
}
-out_tsk:
- put_task_struct(child);
-out:
- unlock_kernel();
+
return ret;
}
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 3063363..a8cb00c 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -55,6 +55,8 @@ struct pt_regs {
#ifdef __powerpc64__
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
/* Size of dummy stack frame allocated when calling signal handler. */
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH -mm 25/43] powerpc ptrace32 user_regset
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
` (14 preceding siblings ...)
2007-12-20 11:58 ` [PATCH -mm 24/43] powerpc compat_sys_ptrace Roland McGrath
@ 2007-12-20 11:59 ` Roland McGrath
15 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2007-12-20 11:59 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This cleans up the 32-bit ptrace syscall support to use user_regset calls
to get at the register data for PTRACE_*REGS* calls.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace32.c | 96 ++++++++++-----------------------------
1 files changed, 25 insertions(+), 71 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 0f6eea0..4c1de6a 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -24,6 +24,7 @@
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
+#include <linux/regset.h>
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
@@ -46,43 +47,21 @@
static long compat_ptrace_old(struct task_struct *child, long request,
long addr, long data)
{
- int ret = -EPERM;
-
- switch(request) {
- case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- CHECK_FULL_REGS(child->thread.regs);
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
- break;
- }
-
- case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- CHECK_FULL_REGS(child->thread.regs);
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
- break;
+ switch (request) {
+ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
+ return copy_regset_to_user(child,
+ task_user_regset_view(current), 0,
+ 0, 32 * sizeof(compat_long_t),
+ compat_ptr(data));
+
+ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
+ return copy_regset_from_user(child,
+ task_user_regset_view(current), 0,
+ 0, 32 * sizeof(compat_long_t),
+ compat_ptr(data));
}
- }
- return ret;
+ return -EPERM;
}
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
@@ -291,42 +270,17 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;
}
- case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
- int ui;
- if (!access_ok(VERIFY_WRITE, (void __user *)data,
- PT_REGS_COUNT * sizeof(int))) {
- ret = -EIO;
- break;
- }
- CHECK_FULL_REGS(child->thread.regs);
- ret = 0;
- for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
- ret |= __put_user(ptrace_get_reg(child, ui),
- (unsigned int __user *) data);
- data += sizeof(int);
- }
- break;
- }
-
- case PTRACE_SETREGS: { /* Set all gp regs in the child. */
- unsigned long tmp;
- int ui;
- if (!access_ok(VERIFY_READ, (void __user *)data,
- PT_REGS_COUNT * sizeof(int))) {
- ret = -EIO;
- break;
- }
- CHECK_FULL_REGS(child->thread.regs);
- ret = 0;
- for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
- ret = __get_user(tmp, (unsigned int __user *) data);
- if (ret)
- break;
- ptrace_put_reg(child, ui, tmp);
- data += sizeof(int);
- }
- break;
- }
+ case PTRACE_GETREGS: /* Get all pt_regs from the child. */
+ return copy_regset_to_user(
+ child, task_user_regset_view(current), 0,
+ 0, PT_REGS_COUNT * sizeof(compat_long_t),
+ compat_ptr(data));
+
+ case PTRACE_SETREGS: /* Set all gp regs in the child. */
+ return copy_regset_from_user(
+ child, task_user_regset_view(current), 0,
+ 0, PT_REGS_COUNT * sizeof(compat_long_t),
+ compat_ptr(data));
case PTRACE_GETFPREGS:
case PTRACE_SETFPREGS:
--
1.5.3.6
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH -mm 18/43] powerpc compat_binfmt_elf
2007-12-20 11:58 ` [PATCH -mm 18/43] powerpc compat_binfmt_elf Roland McGrath
@ 2007-12-21 7:12 ` Christoph Hellwig
2007-12-21 8:56 ` Roland McGrath
0 siblings, 1 reply; 22+ messages in thread
From: Christoph Hellwig @ 2007-12-21 7:12 UTC (permalink / raw)
To: Roland McGrath
Cc: linux-arch, linux-kernel, linuxppc-dev, Paul Mackerras,
Andrew Morton, Linus Torvalds
On Thu, Dec 20, 2007 at 03:58:16AM -0800, Roland McGrath wrote:
> +obj-$(CONFIG_PPC64) += ../../../fs/compat_binfmt_elf.o
Building files from another directory is nasty. Please add a
CONFIG_BINFMT_COMPAT_ELF so we can simply build it in fs/
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH -mm 18/43] powerpc compat_binfmt_elf
2007-12-21 7:12 ` Christoph Hellwig
@ 2007-12-21 8:56 ` Roland McGrath
2007-12-21 17:51 ` Kyle McMartin
0 siblings, 1 reply; 22+ messages in thread
From: Roland McGrath @ 2007-12-21 8:56 UTC (permalink / raw)
To: Christoph Hellwig
Cc: linux-arch, linux-kernel, linuxppc-dev, Paul Mackerras,
Andrew Morton, Linus Torvalds
> On Thu, Dec 20, 2007 at 03:58:16AM -0800, Roland McGrath wrote:
> > +obj-$(CONFIG_PPC64) += ../../../fs/compat_binfmt_elf.o
>
> Building files from another directory is nasty. Please add a
> CONFIG_BINFMT_COMPAT_ELF so we can simply build it in fs/
If that's better, please post the precise Kconfig magic you have in mind to
have it set when it should be.
Thanks,
Roland
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH -mm 18/43] powerpc compat_binfmt_elf
2007-12-21 8:56 ` Roland McGrath
@ 2007-12-21 17:51 ` Kyle McMartin
2007-12-21 19:36 ` Arnd Bergmann
2007-12-21 20:00 ` Sam Ravnborg
0 siblings, 2 replies; 22+ messages in thread
From: Kyle McMartin @ 2007-12-21 17:51 UTC (permalink / raw)
To: Roland McGrath
Cc: linux-arch, linux-kernel, Christoph Hellwig, linuxppc-dev,
Paul Mackerras, Andrew Morton, Linus Torvalds
On Fri, Dec 21, 2007 at 12:56:09AM -0800, Roland McGrath wrote:
> > On Thu, Dec 20, 2007 at 03:58:16AM -0800, Roland McGrath wrote:
> > > +obj-$(CONFIG_PPC64) += ../../../fs/compat_binfmt_elf.o
> >
> > Building files from another directory is nasty. Please add a
> > CONFIG_BINFMT_COMPAT_ELF so we can simply build it in fs/
>
> If that's better, please post the precise Kconfig magic you have in mind to
> have it set when it should be.
>
Just taking a stab that hch means,
config BINFMT_COMPAT_ELF
def_bool n
depends on 64BIT
and then in arch/powerpc/Kconfig
config COMPAT
bool
default y if PPC64
select BINFMT_COMPAT_ELF
or somesuch.
Regards, Kyle
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH -mm 18/43] powerpc compat_binfmt_elf
2007-12-21 17:51 ` Kyle McMartin
@ 2007-12-21 19:36 ` Arnd Bergmann
2007-12-21 20:00 ` Sam Ravnborg
1 sibling, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2007-12-21 19:36 UTC (permalink / raw)
To: linuxppc-dev
Cc: linux-arch, Christoph Hellwig, linux-kernel, Kyle McMartin,
Paul Mackerras, Andrew Morton, Linus Torvalds, Roland McGrath
On Friday 21 December 2007, Kyle McMartin wrote:
> Just taking a stab that hch means,
>=20
> config BINFMT_COMPAT_ELF
> =A0=A0=A0=A0=A0=A0=A0=A0def_bool n
> =A0=A0=A0=A0=A0=A0=A0=A0depends on 64BIT
>=20
I'd call it COMPAT_BINFMT_ELF, for consistency with the file name.
Also, the definition and the depends are redundant if you expect the
option to be autoselected. You can do either of
config COMPAT_BINFMT_ELF
bool
or=20
config COMPAT_BINFMT_ELF
def_bool y
depends on COMPAT
The second option makes sense at the point where all architectures with
compat code are using the same compat_binfmt_elf code.
Arnd <><
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH -mm 18/43] powerpc compat_binfmt_elf
2007-12-21 17:51 ` Kyle McMartin
2007-12-21 19:36 ` Arnd Bergmann
@ 2007-12-21 20:00 ` Sam Ravnborg
1 sibling, 0 replies; 22+ messages in thread
From: Sam Ravnborg @ 2007-12-21 20:00 UTC (permalink / raw)
To: Kyle McMartin
Cc: linux-arch, linux-kernel, Christoph Hellwig, linuxppc-dev,
Paul Mackerras, Andrew Morton, Linus Torvalds, Roland McGrath
On Fri, Dec 21, 2007 at 12:51:06PM -0500, Kyle McMartin wrote:
> On Fri, Dec 21, 2007 at 12:56:09AM -0800, Roland McGrath wrote:
> > > On Thu, Dec 20, 2007 at 03:58:16AM -0800, Roland McGrath wrote:
> > > > +obj-$(CONFIG_PPC64) += ../../../fs/compat_binfmt_elf.o
> > >
> > > Building files from another directory is nasty. Please add a
> > > CONFIG_BINFMT_COMPAT_ELF so we can simply build it in fs/
> >
> > If that's better, please post the precise Kconfig magic you have in mind to
> > have it set when it should be.
Kyle made a proposal but I like to get in to the party too...
> >
>
> Just taking a stab that hch means,
>
> config BINFMT_COMPAT_ELF
> def_bool n
> depends on 64BIT
>
> and then in arch/powerpc/Kconfig
>
> config COMPAT
> bool
> default y if PPC64
> select BINFMT_COMPAT_ELF
>
> or somesuch.
We recently discussed a common prefix for the selctable symbols
and consensus pointed out "HAVE_" so let us try to use it.
I did not quite understand the "depends on 64BIT" in Kyles example.
Does we really want to use compat_binfmt_elf for all archs that
define 64BIT? Anyway I added this in the example below.
fs/Makefile:
obj-$(COMPAT_BINFMT_ELF) += compat_binfmt_elf.o
fs/Kconfig:
config COMPAT_BINFMT_ELF
depends on HAVE_COMPAT_BINFMT_ELF || 64BIT
# COMPAT_BINFMT_ELF must be selected when an
# architecture supoorts ...
config HAVE_COMPAT_BINFMT_ELF
arch/powerpc/Kconfig:
config COMPAT
bool
default PPC64
select HAVE_COMPAT_BINFMT_ELF
In the example above the extra indirection:
HAVE_COMPAT_BINFMT_ELF => COMPAT_BNFMT_ELF is not really needed
but tomorrow when we add another "depends on" to COMPAT_INFMT_ELF
it is needed to avoid the misbehaving select that just ignore the
dependencies and select the symbol anyway.
Sam
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH update -mm 16/43] powerpc user_regset compat
2007-12-20 11:58 ` [PATCH -mm 16/43] powerpc user_regset compat Roland McGrath
@ 2008-01-07 5:40 ` Roland McGrath
0 siblings, 0 replies; 22+ messages in thread
From: Roland McGrath @ 2008-01-07 5:40 UTC (permalink / raw)
To: Andrew Morton, Linus Torvalds
Cc: linux-arch, linuxppc-dev, Paul Mackerras, linux-kernel
This patch replaces my 2007-12-20 patch by the same title, and has to take
its place in the order of applying that whole series.
Further testing revealed a bug that resulted in regset-based core dumps of
32-bit processes on 64-bit kernels having r0..r3 cleared to zero. The fix
(interdiff from original patch) is a trivial pair of lines in two places.
Thanks,
Roland
---
This extends task_user_regset_view CONFIG_PPC64 with support for the 32-bit
view of register state, compatible with what a CONFIG_PPC32 kernel provides.
This will enable generic machine-independent code to access user-mode
threads' registers for debugging and dumping.
Signed-off-by: Roland McGrath <roland@redhat.com>
---
arch/powerpc/kernel/ptrace.c | 162 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 162 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index eb00274..60de9ee 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -501,8 +501,170 @@ static const struct user_regset_view user_ppc_native_view = {
.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
};
+#ifdef CONFIG_PPC64
+#include <linux/compat.h>
+
+static int gpr32_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ const unsigned long *regs = &target->thread.regs->gpr[0];
+ compat_ulong_t *k = kbuf;
+ compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_MSR; --count)
+ *k++ = regs[pos++];
+ else
+ for (; count > 0 && pos < PT_MSR; --count)
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
+ return -EFAULT;
+
+ if (count > 0 && pos == PT_MSR) {
+ reg = get_user_msr(target);
+ if (kbuf)
+ *k++ = reg;
+ else if (__put_user(reg, u++))
+ return -EFAULT;
+ ++pos;
+ --count;
+ }
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
+ *k++ = regs[pos++];
+ else
+ for (; count > 0 && pos < PT_REGS_COUNT; --count)
+ if (__put_user((compat_ulong_t) regs[pos++], u++))
+ return -EFAULT;
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ PT_REGS_COUNT * sizeof(reg), -1);
+}
+
+static int gpr32_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ unsigned long *regs = &target->thread.regs->gpr[0];
+ const compat_ulong_t *k = kbuf;
+ const compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+
+ if (target->thread.regs == NULL)
+ return -EIO;
+
+ CHECK_FULL_REGS(target->thread.regs);
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < PT_MSR; --count)
+ regs[pos++] = *k++;
+ else
+ for (; count > 0 && pos < PT_MSR; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs[pos++] = reg;
+ }
+
+
+ if (count > 0 && pos == PT_MSR) {
+ if (kbuf)
+ reg = *k++;
+ else if (__get_user(reg, u++))
+ return -EFAULT;
+ set_user_msr(target, reg);
+ ++pos;
+ --count;
+ }
+
+ if (kbuf)
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
+ regs[pos++] = *k++;
+ else
+ for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs[pos++] = reg;
+ }
+
+ if (count > 0 && pos == PT_TRAP) {
+ if (kbuf)
+ reg = *k++;
+ else if (__get_user(reg, u++))
+ return -EFAULT;
+ set_user_trap(target, reg);
+ ++pos;
+ --count;
+ }
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ (PT_TRAP + 1) * sizeof(reg), -1);
+}
+
+/*
+ * These are the regset flavors matching the CONFIG_PPC32 native set.
+ */
+static const struct user_regset compat_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+ .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
+ .get = gpr32_get, .set = gpr32_set
+ },
+ [REGSET_FPR] = {
+ .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = fpr_get, .set = fpr_set
+ },
+#ifdef CONFIG_ALTIVEC
+ [REGSET_VMX] = {
+ .core_note_type = NT_PPC_VMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .active = vr_active, .get = vr_get, .set = vr_set
+ },
+#endif
+#ifdef CONFIG_SPE
+ [REGSET_SPE] = {
+ .n = 35,
+ .size = sizeof(u32), .align = sizeof(u32),
+ .active = evr_active, .get = evr_get, .set = evr_set
+ },
+#endif
+};
+
+static const struct user_regset_view user_ppc_compat_view = {
+ .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
+ .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
+};
+#endif /* CONFIG_PPC64 */
+
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
+#ifdef CONFIG_PPC64
+ if (test_tsk_thread_flag(task, TIF_32BIT))
+ return &user_ppc_compat_view;
+#endif
return &user_ppc_native_view;
}
^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-01-07 5:41 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20071220115200.C767E26F98A@magilla.localdomain>
2007-12-20 11:57 ` [PATCH -mm 10/43] powerpc user_regset fpregs Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 11/43] powerpc user_regset altivec Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 12/43] powerpc user_regset spe Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 13/43] powerpc ptrace special regs Roland McGrath
2007-12-20 11:57 ` [PATCH -mm 14/43] powerpc user_regset gpr Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 15/43] powerpc user_regset_view Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 16/43] powerpc user_regset compat Roland McGrath
2008-01-07 5:40 ` [PATCH update " Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 17/43] powerpc CORE_DUMP_USE_REGSET Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 18/43] powerpc compat_binfmt_elf Roland McGrath
2007-12-21 7:12 ` Christoph Hellwig
2007-12-21 8:56 ` Roland McGrath
2007-12-21 17:51 ` Kyle McMartin
2007-12-21 19:36 ` Arnd Bergmann
2007-12-21 20:00 ` Sam Ravnborg
2007-12-20 11:58 ` [PATCH -mm 19/43] powerpc core dump cleanup Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 20/43] powerpc SPE core dump Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 21/43] powerpc ptrace user_regset Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 22/43] powerpc ptrace generic peekdata/pokedata Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 23/43] powerpc compat_ptrace_request Roland McGrath
2007-12-20 11:58 ` [PATCH -mm 24/43] powerpc compat_sys_ptrace Roland McGrath
2007-12-20 11:59 ` [PATCH -mm 25/43] powerpc ptrace32 user_regset Roland McGrath
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).