diff options
Diffstat (limited to 'arch/blackfin/kernel/ptrace.c')
-rw-r--r-- | arch/blackfin/kernel/ptrace.c | 118 |
1 files changed, 51 insertions, 67 deletions
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 14118e40f18f..9536c1e2d1c7 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
26 | #include <asm/mem_map.h> | 26 | #include <asm/mem_map.h> |
27 | 27 | ||
28 | #define TEXT_OFFSET 0 | ||
29 | /* | 28 | /* |
30 | * does not yet catch signals sent when the child dies. | 29 | * does not yet catch signals sent when the child dies. |
31 | * in exit.c or in signal.c. | 30 | * in exit.c or in signal.c. |
@@ -43,7 +42,7 @@ | |||
43 | * kernel stack will not be empty on entry to the kernel, so | 42 | * kernel stack will not be empty on entry to the kernel, so |
44 | * ptracing these tasks will fail. | 43 | * ptracing these tasks will fail. |
45 | */ | 44 | */ |
46 | static inline struct pt_regs *get_user_regs(struct task_struct *task) | 45 | static inline struct pt_regs *task_pt_regs(struct task_struct *task) |
47 | { | 46 | { |
48 | return (struct pt_regs *) | 47 | return (struct pt_regs *) |
49 | ((unsigned long)task_stack_page(task) + | 48 | ((unsigned long)task_stack_page(task) + |
@@ -56,7 +55,7 @@ static inline struct pt_regs *get_user_regs(struct task_struct *task) | |||
56 | static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) | 55 | static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) |
57 | { | 56 | { |
58 | struct pt_regs regs; | 57 | struct pt_regs regs; |
59 | memcpy(®s, get_user_regs(tsk), sizeof(regs)); | 58 | memcpy(®s, task_pt_regs(tsk), sizeof(regs)); |
60 | regs.usp = tsk->thread.usp; | 59 | regs.usp = tsk->thread.usp; |
61 | return copy_to_user(uregs, ®s, sizeof(struct pt_regs)) ? -EFAULT : 0; | 60 | return copy_to_user(uregs, ®s, sizeof(struct pt_regs)) ? -EFAULT : 0; |
62 | } | 61 | } |
@@ -69,40 +68,49 @@ static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) | |||
69 | /* | 68 | /* |
70 | * Get contents of register REGNO in task TASK. | 69 | * Get contents of register REGNO in task TASK. |
71 | */ | 70 | */ |
72 | static inline long get_reg(struct task_struct *task, int regno) | 71 | static inline long |
72 | get_reg(struct task_struct *task, long regno, unsigned long __user *datap) | ||
73 | { | 73 | { |
74 | unsigned char *reg_ptr; | 74 | long tmp; |
75 | struct pt_regs *regs = task_pt_regs(task); | ||
75 | 76 | ||
76 | struct pt_regs *regs = | 77 | if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0) |
77 | (struct pt_regs *)((unsigned long)task_stack_page(task) + | 78 | return -EIO; |
78 | (THREAD_SIZE - sizeof(struct pt_regs))); | ||
79 | reg_ptr = (char *)regs; | ||
80 | 79 | ||
81 | switch (regno) { | 80 | switch (regno) { |
81 | case PT_TEXT_ADDR: | ||
82 | tmp = task->mm->start_code; | ||
83 | break; | ||
84 | case PT_TEXT_END_ADDR: | ||
85 | tmp = task->mm->end_code; | ||
86 | break; | ||
87 | case PT_DATA_ADDR: | ||
88 | tmp = task->mm->start_data; | ||
89 | break; | ||
82 | case PT_USP: | 90 | case PT_USP: |
83 | return task->thread.usp; | 91 | tmp = task->thread.usp; |
92 | break; | ||
84 | default: | 93 | default: |
85 | if (regno <= 216) | 94 | if (regno < sizeof(*regs)) { |
86 | return *(long *)(reg_ptr + regno); | 95 | void *reg_ptr = regs; |
96 | tmp = *(long *)(reg_ptr + regno); | ||
97 | } else | ||
98 | return -EIO; | ||
87 | } | 99 | } |
88 | /* slight mystery ... never seems to come here but kernel misbehaves without this code! */ | ||
89 | 100 | ||
90 | printk(KERN_WARNING "Request to get for unknown register %d\n", regno); | 101 | return put_user(tmp, datap); |
91 | return 0; | ||
92 | } | 102 | } |
93 | 103 | ||
94 | /* | 104 | /* |
95 | * Write contents of register REGNO in task TASK. | 105 | * Write contents of register REGNO in task TASK. |
96 | */ | 106 | */ |
97 | static inline int | 107 | static inline int |
98 | put_reg(struct task_struct *task, int regno, unsigned long data) | 108 | put_reg(struct task_struct *task, long regno, unsigned long data) |
99 | { | 109 | { |
100 | char *reg_ptr; | 110 | struct pt_regs *regs = task_pt_regs(task); |
101 | 111 | ||
102 | struct pt_regs *regs = | 112 | if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0) |
103 | (struct pt_regs *)((unsigned long)task_stack_page(task) + | 113 | return -EIO; |
104 | (THREAD_SIZE - sizeof(struct pt_regs))); | ||
105 | reg_ptr = (char *)regs; | ||
106 | 114 | ||
107 | switch (regno) { | 115 | switch (regno) { |
108 | case PT_PC: | 116 | case PT_PC: |
@@ -119,10 +127,18 @@ put_reg(struct task_struct *task, int regno, unsigned long data) | |||
119 | regs->usp = data; | 127 | regs->usp = data; |
120 | task->thread.usp = data; | 128 | task->thread.usp = data; |
121 | break; | 129 | break; |
130 | case PT_SYSCFG: /* don't let userspace screw with this */ | ||
131 | if ((data & ~1) != 0x6) | ||
132 | pr_warning("ptrace: ignore syscfg write of %#lx\n", data); | ||
133 | break; /* regs->syscfg = data; break; */ | ||
122 | default: | 134 | default: |
123 | if (regno <= 216) | 135 | if (regno < sizeof(*regs)) { |
124 | *(long *)(reg_ptr + regno) = data; | 136 | void *reg_offset = regs; |
137 | *(long *)(reg_offset + regno) = data; | ||
138 | } | ||
139 | /* Ignore writes to pseudo registers */ | ||
125 | } | 140 | } |
141 | |||
126 | return 0; | 142 | return 0; |
127 | } | 143 | } |
128 | 144 | ||
@@ -231,40 +247,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
231 | break; | 247 | break; |
232 | } | 248 | } |
233 | 249 | ||
234 | /* read the word at location addr in the USER area. */ | ||
235 | case PTRACE_PEEKUSR: | ||
236 | { | ||
237 | unsigned long tmp; | ||
238 | ret = -EIO; | ||
239 | tmp = 0; | ||
240 | if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { | ||
241 | printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning " | ||
242 | "0 - %x sizeof(pt_regs) is %lx\n", | ||
243 | (int)addr, sizeof(struct pt_regs)); | ||
244 | break; | ||
245 | } | ||
246 | if (addr == sizeof(struct pt_regs)) { | ||
247 | /* PT_TEXT_ADDR */ | ||
248 | tmp = child->mm->start_code + TEXT_OFFSET; | ||
249 | } else if (addr == (sizeof(struct pt_regs) + 4)) { | ||
250 | /* PT_TEXT_END_ADDR */ | ||
251 | tmp = child->mm->end_code; | ||
252 | } else if (addr == (sizeof(struct pt_regs) + 8)) { | ||
253 | /* PT_DATA_ADDR */ | ||
254 | tmp = child->mm->start_data; | ||
255 | #ifdef CONFIG_BINFMT_ELF_FDPIC | ||
256 | } else if (addr == (sizeof(struct pt_regs) + 12)) { | ||
257 | goto case_PTRACE_GETFDPIC_EXEC; | ||
258 | } else if (addr == (sizeof(struct pt_regs) + 16)) { | ||
259 | goto case_PTRACE_GETFDPIC_INTERP; | ||
260 | #endif | ||
261 | } else { | ||
262 | tmp = get_reg(child, addr); | ||
263 | } | ||
264 | ret = put_user(tmp, datap); | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | #ifdef CONFIG_BINFMT_ELF_FDPIC | 250 | #ifdef CONFIG_BINFMT_ELF_FDPIC |
269 | case PTRACE_GETFDPIC: { | 251 | case PTRACE_GETFDPIC: { |
270 | unsigned long tmp = 0; | 252 | unsigned long tmp = 0; |
@@ -327,19 +309,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
327 | break; | 309 | break; |
328 | } | 310 | } |
329 | 311 | ||
330 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | 312 | case PTRACE_PEEKUSR: |
331 | ret = -EIO; | 313 | switch (addr) { |
332 | if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { | 314 | #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */ |
333 | printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n"); | 315 | case PT_FDPIC_EXEC: goto case_PTRACE_GETFDPIC_EXEC; |
334 | break; | 316 | case PT_FDPIC_INTERP: goto case_PTRACE_GETFDPIC_INTERP; |
317 | #endif | ||
318 | default: | ||
319 | ret = get_reg(child, addr, datap); | ||
335 | } | 320 | } |
321 | pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret); | ||
322 | break; | ||
336 | 323 | ||
337 | /* Ignore writes to SYSCFG and other pseudo regs */ | 324 | case PTRACE_POKEUSR: |
338 | if (addr >= PT_SYSCFG) { | ||
339 | ret = 0; | ||
340 | break; | ||
341 | } | ||
342 | ret = put_reg(child, addr, data); | 325 | ret = put_reg(child, addr, data); |
326 | pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret); | ||
343 | break; | 327 | break; |
344 | 328 | ||
345 | case PTRACE_GETREGS: | 329 | case PTRACE_GETREGS: |