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/processor.h>
24 #include <asm/asm-offsets.h>
26 #include <asm/fixed_code.h>
27 #include <asm/cacheflush.h>
28 #include <asm/mem_map.h>
29 #include <asm/mmu_context.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
, unsigned long regno
,
41 unsigned long __user
*datap
)
44 struct pt_regs
*regs
= task_pt_regs(task
);
46 if (regno
& 3 || regno
> PT_LAST_PSEUDO
)
51 tmp
= task
->mm
->start_code
;
53 case PT_TEXT_END_ADDR
:
54 tmp
= task
->mm
->end_code
;
57 tmp
= task
->mm
->start_data
;
60 tmp
= task
->thread
.usp
;
63 if (regno
< sizeof(*regs
)) {
65 tmp
= *(long *)(reg_ptr
+ regno
);
70 return put_user(tmp
, datap
);
74 * Write contents of register REGNO in task TASK.
77 put_reg(struct task_struct
*task
, unsigned long regno
, unsigned long data
)
79 struct pt_regs
*regs
= task_pt_regs(task
);
81 if (regno
& 3 || regno
> PT_LAST_PSEUDO
)
86 /*********************************************************************/
87 /* At this point the kernel is most likely in exception. */
88 /* The RETX register will be used to populate the pc of the process. */
89 /*********************************************************************/
94 break; /* regs->retx = data; break; */
97 task
->thread
.usp
= data
;
99 case PT_SYSCFG
: /* don't let userspace screw with this */
100 if ((data
& ~1) != 0x6)
101 pr_warning("ptrace: ignore syscfg write of %#lx\n", data
);
102 break; /* regs->syscfg = data; break; */
104 if (regno
< sizeof(*regs
)) {
105 void *reg_offset
= regs
;
106 *(long *)(reg_offset
+ regno
) = data
;
108 /* Ignore writes to pseudo registers */
115 * check that an address falls within the bounds of the target process's memory mappings
118 is_user_addr_valid(struct task_struct
*child
, unsigned long start
, unsigned long len
)
121 struct vm_area_struct
*vma
;
122 struct sram_list_struct
*sraml
;
125 if (start
+ len
< start
)
128 down_read(&child
->mm
->mmap_sem
);
129 vma
= find_vma(child
->mm
, start
);
130 valid
= vma
&& start
>= vma
->vm_start
&& start
+ len
<= vma
->vm_end
;
131 up_read(&child
->mm
->mmap_sem
);
135 for (sraml
= child
->mm
->context
.sram_list
; sraml
; sraml
= sraml
->next
)
136 if (start
>= (unsigned long)sraml
->addr
137 && start
+ len
< (unsigned long)sraml
->addr
+ sraml
->length
)
140 if (start
>= FIXED_CODE_START
&& start
+ len
< FIXED_CODE_END
)
143 #ifdef CONFIG_APP_STACK_L1
144 if (child
->mm
->context
.l1_stack_save
)
145 if (start
>= (unsigned long)l1_stack_base
&&
146 start
+ len
< (unsigned long)l1_stack_base
+ l1_stack_len
)
154 * retrieve the contents of Blackfin userspace general registers
156 static int genregs_get(struct task_struct
*target
,
157 const struct user_regset
*regset
,
158 unsigned int pos
, unsigned int count
,
159 void *kbuf
, void __user
*ubuf
)
161 struct pt_regs
*regs
= task_pt_regs(target
);
165 regs
->usp
= target
->thread
.usp
;
167 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
168 regs
, 0, sizeof(*regs
));
172 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
177 * update the contents of the Blackfin userspace general registers
179 static int genregs_set(struct task_struct
*target
,
180 const struct user_regset
*regset
,
181 unsigned int pos
, unsigned int count
,
182 const void *kbuf
, const void __user
*ubuf
)
184 struct pt_regs
*regs
= task_pt_regs(target
);
187 /* Don't let people set SYSCFG (it's at the end of pt_regs) */
188 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
194 target
->thread
.usp
= regs
->usp
;
195 /* regs->retx = regs->pc; */
197 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
202 * Define the register sets available on the Blackfin under Linux
208 static const struct user_regset bfin_regsets
[] = {
210 .core_note_type
= NT_PRSTATUS
,
211 .n
= sizeof(struct pt_regs
) / sizeof(long),
212 .size
= sizeof(long),
213 .align
= sizeof(long),
219 static const struct user_regset_view user_bfin_native_view
= {
221 .e_machine
= EM_BLACKFIN
,
222 .regsets
= bfin_regsets
,
223 .n
= ARRAY_SIZE(bfin_regsets
),
226 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
228 return &user_bfin_native_view
;
231 void user_enable_single_step(struct task_struct
*child
)
233 struct pt_regs
*regs
= task_pt_regs(child
);
234 regs
->syscfg
|= SYSCFG_SSSTEP
;
236 set_tsk_thread_flag(child
, TIF_SINGLESTEP
);
239 void user_disable_single_step(struct task_struct
*child
)
241 struct pt_regs
*regs
= task_pt_regs(child
);
242 regs
->syscfg
&= ~SYSCFG_SSSTEP
;
244 clear_tsk_thread_flag(child
, TIF_SINGLESTEP
);
247 long arch_ptrace(struct task_struct
*child
, long request
,
248 unsigned long addr
, unsigned long data
)
251 unsigned long __user
*datap
= (unsigned long __user
*)data
;
252 void *paddr
= (void *)addr
;
255 /* when I and D space are separate, these will need to be fixed. */
256 case PTRACE_PEEKDATA
:
257 pr_debug("ptrace: PEEKDATA\n");
259 case PTRACE_PEEKTEXT
: /* read word at location addr. */
261 unsigned long tmp
= 0;
262 int copied
= 0, to_copy
= sizeof(tmp
);
265 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr
, to_copy
);
266 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
268 pr_debug("ptrace: user address is valid\n");
270 switch (bfin_mem_access_type(addr
, to_copy
)) {
271 case BFIN_MEM_ACCESS_CORE
:
272 case BFIN_MEM_ACCESS_CORE_ONLY
:
273 copied
= access_process_vm(child
, addr
, &tmp
,
278 /* hrm, why didn't that work ... maybe no mapping */
279 if (addr
>= FIXED_CODE_START
&&
280 addr
+ to_copy
<= FIXED_CODE_END
) {
281 copy_from_user_page(0, 0, 0, &tmp
, paddr
, to_copy
);
283 } else if (addr
>= BOOT_ROM_START
) {
284 memcpy(&tmp
, paddr
, to_copy
);
289 case BFIN_MEM_ACCESS_DMA
:
290 if (safe_dma_memcpy(&tmp
, paddr
, to_copy
))
293 case BFIN_MEM_ACCESS_ITEST
:
294 if (isram_memcpy(&tmp
, paddr
, to_copy
))
302 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied
, tmp
);
303 if (copied
== to_copy
)
304 ret
= put_user(tmp
, datap
);
308 /* when I and D space are separate, this will have to be fixed. */
309 case PTRACE_POKEDATA
:
310 pr_debug("ptrace: PTRACE_PEEKDATA\n");
312 case PTRACE_POKETEXT
: /* write the word at location addr. */
314 int copied
= 0, to_copy
= sizeof(data
);
317 pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n",
318 addr
, to_copy
, data
);
319 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
321 pr_debug("ptrace: user address is valid\n");
323 switch (bfin_mem_access_type(addr
, to_copy
)) {
324 case BFIN_MEM_ACCESS_CORE
:
325 case BFIN_MEM_ACCESS_CORE_ONLY
:
326 copied
= access_process_vm(child
, addr
, &data
,
329 case BFIN_MEM_ACCESS_DMA
:
330 if (safe_dma_memcpy(paddr
, &data
, to_copy
))
333 case BFIN_MEM_ACCESS_ITEST
:
334 if (isram_memcpy(paddr
, &data
, to_copy
))
342 pr_debug("ptrace: copied size %d\n", copied
);
343 if (copied
== to_copy
)
350 #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
352 request
= PTRACE_GETFDPIC
;
353 addr
= PTRACE_GETFDPIC_EXEC
;
355 case PT_FDPIC_INTERP
:
356 request
= PTRACE_GETFDPIC
;
357 addr
= PTRACE_GETFDPIC_INTERP
;
361 ret
= get_reg(child
, addr
, datap
);
363 pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr
, data
, ret
);
367 ret
= put_reg(child
, addr
, data
);
368 pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr
, data
, ret
);
372 pr_debug("ptrace: PTRACE_GETREGS\n");
373 return copy_regset_to_user(child
, &user_bfin_native_view
,
375 0, sizeof(struct pt_regs
),
379 pr_debug("ptrace: PTRACE_SETREGS\n");
380 return copy_regset_from_user(child
, &user_bfin_native_view
,
382 0, sizeof(struct pt_regs
),
387 ret
= ptrace_request(child
, request
, addr
, data
);
394 asmlinkage
int syscall_trace_enter(struct pt_regs
*regs
)
398 if (test_thread_flag(TIF_SYSCALL_TRACE
))
399 ret
= tracehook_report_syscall_entry(regs
);
404 asmlinkage
void syscall_trace_leave(struct pt_regs
*regs
)
408 step
= test_thread_flag(TIF_SINGLESTEP
);
409 if (step
|| test_thread_flag(TIF_SYSCALL_TRACE
))
410 tracehook_report_syscall_exit(regs
, step
);