aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-10-14 16:48:00 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-10-15 15:39:44 -0400
commitce7f2a39675ea5e8e27b3f3bb03e5041c7d10412 (patch)
tree5552e14b279cac5acc56c2b9cd3114d8e612a078 /arch/tile
parentc569cac8b69397d8bc80f95bc6edf13ed902e28b (diff)
arch/tile: make ptrace() work properly for TILE-Gx COMPAT mode
Previously, we tried to pass 64-bit arguments through the "COMPAT" mode 32-bit syscall API, which turned out not to work well. Now we just use straight 32-bit arguments in COMPAT mode, thus requiring individual registers to be read/written with two syscalls. Of course this is uncommon, since usually all the registers are read or written at once. The restructuring applies to all the tile platforms, but is plausibly better than the original code in any case. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile')
-rw-r--r--arch/tile/kernel/compat.c4
-rw-r--r--arch/tile/kernel/ptrace.c78
2 files changed, 38 insertions, 44 deletions
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index 5f24e54bf3c5..77739cdd9462 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -154,8 +154,8 @@ long tile_compat_sys_msgrcv(int msqid,
154#define compat_sys_fstat64 sys_newfstat 154#define compat_sys_fstat64 sys_newfstat
155#define compat_sys_fstatat64 sys_newfstatat 155#define compat_sys_fstatat64 sys_newfstatat
156 156
157/* Pass full 64-bit values through ptrace. */ 157/* The native sys_ptrace dynamically handles compat binaries. */
158#define compat_sys_ptrace tile_compat_sys_ptrace 158#define compat_sys_ptrace sys_ptrace
159 159
160/* Call the trampolines to manage pt_regs where necessary. */ 160/* Call the trampolines to manage pt_regs where necessary. */
161#define compat_sys_execve _compat_sys_execve 161#define compat_sys_execve _compat_sys_execve
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index 7161bd03d2fd..5b20c2874d51 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -32,25 +32,6 @@ void user_disable_single_step(struct task_struct *child)
32} 32}
33 33
34/* 34/*
35 * This routine will put a word on the process's privileged stack.
36 */
37static void putreg(struct task_struct *task,
38 unsigned long addr, unsigned long value)
39{
40 unsigned int regno = addr / sizeof(unsigned long);
41 struct pt_regs *childregs = task_pt_regs(task);
42 childregs->regs[regno] = value;
43 childregs->flags |= PT_FLAGS_RESTORE_REGS;
44}
45
46static unsigned long getreg(struct task_struct *task, unsigned long addr)
47{
48 unsigned int regno = addr / sizeof(unsigned long);
49 struct pt_regs *childregs = task_pt_regs(task);
50 return childregs->regs[regno];
51}
52
53/*
54 * Called by kernel/ptrace.c when detaching.. 35 * Called by kernel/ptrace.c when detaching..
55 */ 36 */
56void ptrace_disable(struct task_struct *child) 37void ptrace_disable(struct task_struct *child)
@@ -66,59 +47,72 @@ void ptrace_disable(struct task_struct *child)
66 47
67long arch_ptrace(struct task_struct *child, long request, long addr, long data) 48long arch_ptrace(struct task_struct *child, long request, long addr, long data)
68{ 49{
69 unsigned long __user *datap; 50 unsigned long __user *datap = (long __user __force *)data;
70 unsigned long tmp; 51 unsigned long tmp;
71 int i; 52 int i;
72 long ret = -EIO; 53 long ret = -EIO;
73 54 unsigned long *childregs;
74#ifdef CONFIG_COMPAT 55 char *childreg;
75 if (task_thread_info(current)->status & TS_COMPAT)
76 data = (u32)data;
77 if (task_thread_info(child)->status & TS_COMPAT)
78 addr = (u32)addr;
79#endif
80 datap = (unsigned long __user __force *)data;
81 56
82 switch (request) { 57 switch (request) {
83 58
84 case PTRACE_PEEKUSR: /* Read register from pt_regs. */ 59 case PTRACE_PEEKUSR: /* Read register from pt_regs. */
85 if (addr & (sizeof(data)-1))
86 break;
87 if (addr < 0 || addr >= PTREGS_SIZE) 60 if (addr < 0 || addr >= PTREGS_SIZE)
88 break; 61 break;
89 tmp = getreg(child, addr); /* Read register */ 62 childreg = (char *)task_pt_regs(child) + addr;
90 ret = put_user(tmp, datap); 63#ifdef CONFIG_COMPAT
64 if (is_compat_task()) {
65 if (addr & (sizeof(compat_long_t)-1))
66 break;
67 ret = put_user(*(compat_long_t *)childreg,
68 (compat_long_t __user *)datap);
69 } else
70#endif
71 {
72 if (addr & (sizeof(long)-1))
73 break;
74 ret = put_user(*(long *)childreg, datap);
75 }
91 break; 76 break;
92 77
93 case PTRACE_POKEUSR: /* Write register in pt_regs. */ 78 case PTRACE_POKEUSR: /* Write register in pt_regs. */
94 if (addr & (sizeof(data)-1))
95 break;
96 if (addr < 0 || addr >= PTREGS_SIZE) 79 if (addr < 0 || addr >= PTREGS_SIZE)
97 break; 80 break;
98 putreg(child, addr, data); /* Write register */ 81 childreg = (char *)task_pt_regs(child) + addr;
82#ifdef CONFIG_COMPAT
83 if (is_compat_task()) {
84 if (addr & (sizeof(compat_long_t)-1))
85 break;
86 *(compat_long_t *)childreg = data;
87 } else
88#endif
89 {
90 if (addr & (sizeof(long)-1))
91 break;
92 *(long *)childreg = data;
93 }
99 ret = 0; 94 ret = 0;
100 break; 95 break;
101 96
102 case PTRACE_GETREGS: /* Get all registers from the child. */ 97 case PTRACE_GETREGS: /* Get all registers from the child. */
103 if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE)) 98 if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
104 break; 99 break;
105 for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) { 100 childregs = (long *)task_pt_regs(child);
106 ret = __put_user(getreg(child, i), datap); 101 for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) {
102 ret = __put_user(childregs[i], &datap[i]);
107 if (ret != 0) 103 if (ret != 0)
108 break; 104 break;
109 datap++;
110 } 105 }
111 break; 106 break;
112 107
113 case PTRACE_SETREGS: /* Set all registers in the child. */ 108 case PTRACE_SETREGS: /* Set all registers in the child. */
114 if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE)) 109 if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
115 break; 110 break;
116 for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) { 111 childregs = (long *)task_pt_regs(child);
117 ret = __get_user(tmp, datap); 112 for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) {
113 ret = __get_user(childregs[i], &datap[i]);
118 if (ret != 0) 114 if (ret != 0)
119 break; 115 break;
120 putreg(child, i, tmp);
121 datap++;
122 } 116 }
123 break; 117 break;
124 118