2 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
3 * these modifications are Copyright 2004-2010 Analog Devices Inc.
5 * Licensed under the GPL-2
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
11 #include <linux/smp.h>
12 #include <linux/elf.h>
13 #include <linux/errno.h>
14 #include <linux/ptrace.h>
15 #include <linux/user.h>
16 #include <linux/regset.h>
17 #include <linux/signal.h>
18 #include <linux/tracehook.h>
19 #include <linux/uaccess.h>
22 #include <asm/pgtable.h>
23 #include <asm/system.h>
24 #include <asm/processor.h>
25 #include <asm/asm-offsets.h>
27 #include <asm/fixed_code.h>
28 #include <asm/cacheflush.h>
29 #include <asm/mem_map.h>
32 * does not yet catch signals sent when the child dies.
33 * in exit.c or in signal.c.
37 * Get contents of register REGNO in task TASK.
40 get_reg(struct task_struct
*task
, long regno
, unsigned long __user
*datap
)
43 struct pt_regs
*regs
= task_pt_regs(task
);
45 if (regno
& 3 || regno
> PT_LAST_PSEUDO
|| regno
< 0)
50 tmp
= task
->mm
->start_code
;
52 case PT_TEXT_END_ADDR
:
53 tmp
= task
->mm
->end_code
;
56 tmp
= task
->mm
->start_data
;
59 tmp
= task
->thread
.usp
;
62 if (regno
< sizeof(*regs
)) {
64 tmp
= *(long *)(reg_ptr
+ regno
);
69 return put_user(tmp
, datap
);
73 * Write contents of register REGNO in task TASK.
76 put_reg(struct task_struct
*task
, long regno
, unsigned long data
)
78 struct pt_regs
*regs
= task_pt_regs(task
);
80 if (regno
& 3 || regno
> PT_LAST_PSEUDO
|| regno
< 0)
85 /*********************************************************************/
86 /* At this point the kernel is most likely in exception. */
87 /* The RETX register will be used to populate the pc of the process. */
88 /*********************************************************************/
93 break; /* regs->retx = data; break; */
96 task
->thread
.usp
= data
;
98 case PT_SYSCFG
: /* don't let userspace screw with this */
99 if ((data
& ~1) != 0x6)
100 pr_warning("ptrace: ignore syscfg write of %#lx\n", data
);
101 break; /* regs->syscfg = data; break; */
103 if (regno
< sizeof(*regs
)) {
104 void *reg_offset
= regs
;
105 *(long *)(reg_offset
+ regno
) = data
;
107 /* Ignore writes to pseudo registers */
114 * check that an address falls within the bounds of the target process's memory mappings
116 static inline int is_user_addr_valid(struct task_struct
*child
,
117 unsigned long start
, unsigned long len
)
119 struct vm_area_struct
*vma
;
120 struct sram_list_struct
*sraml
;
123 if (start
+ len
< start
)
126 vma
= find_vma(child
->mm
, start
);
127 if (vma
&& start
>= vma
->vm_start
&& start
+ len
<= vma
->vm_end
)
130 for (sraml
= child
->mm
->context
.sram_list
; sraml
; sraml
= sraml
->next
)
131 if (start
>= (unsigned long)sraml
->addr
132 && start
+ len
< (unsigned long)sraml
->addr
+ sraml
->length
)
135 if (start
>= FIXED_CODE_START
&& start
+ len
< FIXED_CODE_END
)
142 * retrieve the contents of Blackfin userspace general registers
144 static int genregs_get(struct task_struct
*target
,
145 const struct user_regset
*regset
,
146 unsigned int pos
, unsigned int count
,
147 void *kbuf
, void __user
*ubuf
)
149 struct pt_regs
*regs
= task_pt_regs(target
);
153 regs
->usp
= target
->thread
.usp
;
155 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
156 regs
, 0, sizeof(*regs
));
160 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
165 * update the contents of the Blackfin userspace general registers
167 static int genregs_set(struct task_struct
*target
,
168 const struct user_regset
*regset
,
169 unsigned int pos
, unsigned int count
,
170 const void *kbuf
, const void __user
*ubuf
)
172 struct pt_regs
*regs
= task_pt_regs(target
);
175 /* Don't let people set SYSCFG (it's at the end of pt_regs) */
176 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
182 target
->thread
.usp
= regs
->usp
;
183 /* regs->retx = regs->pc; */
185 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
190 * Define the register sets available on the Blackfin under Linux
196 static const struct user_regset bfin_regsets
[] = {
198 .core_note_type
= NT_PRSTATUS
,
199 .n
= sizeof(struct pt_regs
) / sizeof(long),
200 .size
= sizeof(long),
201 .align
= sizeof(long),
207 static const struct user_regset_view user_bfin_native_view
= {
209 .e_machine
= EM_BLACKFIN
,
210 .regsets
= bfin_regsets
,
211 .n
= ARRAY_SIZE(bfin_regsets
),
214 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
216 return &user_bfin_native_view
;
219 void user_enable_single_step(struct task_struct
*child
)
221 struct pt_regs
*regs
= task_pt_regs(child
);
222 regs
->syscfg
|= SYSCFG_SSSTEP
;
224 set_tsk_thread_flag(child
, TIF_SINGLESTEP
);
227 void user_disable_single_step(struct task_struct
*child
)
229 struct pt_regs
*regs
= task_pt_regs(child
);
230 regs
->syscfg
&= ~SYSCFG_SSSTEP
;
232 clear_tsk_thread_flag(child
, TIF_SINGLESTEP
);
235 long arch_ptrace(struct task_struct
*child
, long request
, long addr
, long data
)
238 unsigned long __user
*datap
= (unsigned long __user
*)data
;
239 void *paddr
= (void *)addr
;
242 /* when I and D space are separate, these will need to be fixed. */
243 case PTRACE_PEEKDATA
:
244 pr_debug("ptrace: PEEKDATA\n");
246 case PTRACE_PEEKTEXT
: /* read word at location addr. */
248 unsigned long tmp
= 0;
249 int copied
= 0, to_copy
= sizeof(tmp
);
252 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr
, to_copy
);
253 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
255 pr_debug("ptrace: user address is valid\n");
257 switch (bfin_mem_access_type(addr
, to_copy
)) {
258 case BFIN_MEM_ACCESS_CORE
:
259 case BFIN_MEM_ACCESS_CORE_ONLY
:
260 copied
= access_process_vm(child
, addr
, &tmp
,
265 /* hrm, why didn't that work ... maybe no mapping */
266 if (addr
>= FIXED_CODE_START
&&
267 addr
+ to_copy
<= FIXED_CODE_END
) {
268 copy_from_user_page(0, 0, 0, &tmp
, paddr
, to_copy
);
270 } else if (addr
>= BOOT_ROM_START
) {
271 memcpy(&tmp
, paddr
, to_copy
);
276 case BFIN_MEM_ACCESS_DMA
:
277 if (safe_dma_memcpy(&tmp
, paddr
, to_copy
))
280 case BFIN_MEM_ACCESS_ITEST
:
281 if (isram_memcpy(&tmp
, paddr
, to_copy
))
289 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied
, tmp
);
290 if (copied
== to_copy
)
291 ret
= put_user(tmp
, datap
);
295 /* when I and D space are separate, this will have to be fixed. */
296 case PTRACE_POKEDATA
:
297 pr_debug("ptrace: PTRACE_PEEKDATA\n");
299 case PTRACE_POKETEXT
: /* write the word at location addr. */
301 int copied
= 0, to_copy
= sizeof(data
);
304 pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n",
305 addr
, to_copy
, data
);
306 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
308 pr_debug("ptrace: user address is valid\n");
310 switch (bfin_mem_access_type(addr
, to_copy
)) {
311 case BFIN_MEM_ACCESS_CORE
:
312 case BFIN_MEM_ACCESS_CORE_ONLY
:
313 copied
= access_process_vm(child
, addr
, &data
,
316 case BFIN_MEM_ACCESS_DMA
:
317 if (safe_dma_memcpy(paddr
, &data
, to_copy
))
320 case BFIN_MEM_ACCESS_ITEST
:
321 if (isram_memcpy(paddr
, &data
, to_copy
))
329 pr_debug("ptrace: copied size %d\n", copied
);
330 if (copied
== to_copy
)
337 #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
339 request
= PTRACE_GETFDPIC
;
340 addr
= PTRACE_GETFDPIC_EXEC
;
342 case PT_FDPIC_INTERP
:
343 request
= PTRACE_GETFDPIC
;
344 addr
= PTRACE_GETFDPIC_INTERP
;
348 ret
= get_reg(child
, addr
, datap
);
350 pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr
, data
, ret
);
354 ret
= put_reg(child
, addr
, data
);
355 pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr
, data
, ret
);
359 pr_debug("ptrace: PTRACE_GETREGS\n");
360 return copy_regset_to_user(child
, &user_bfin_native_view
,
362 0, sizeof(struct pt_regs
),
363 (void __user
*)data
);
366 pr_debug("ptrace: PTRACE_SETREGS\n");
367 return copy_regset_from_user(child
, &user_bfin_native_view
,
369 0, sizeof(struct pt_regs
),
370 (const void __user
*)data
);
374 ret
= ptrace_request(child
, request
, addr
, data
);
381 asmlinkage
int syscall_trace_enter(struct pt_regs
*regs
)
385 if (test_thread_flag(TIF_SYSCALL_TRACE
))
386 ret
= tracehook_report_syscall_entry(regs
);
391 asmlinkage
void syscall_trace_leave(struct pt_regs
*regs
)
395 step
= test_thread_flag(TIF_SINGLESTEP
);
396 if (step
|| test_thread_flag(TIF_SYSCALL_TRACE
))
397 tracehook_report_syscall_exit(regs
, step
);